### Basic Turbowatch Setup and Execution Source: https://github.com/gajus/turbowatch/blob/main/README.md Install Turbowatch, create a configuration file (turbowatch.ts), and execute it using npm exec. The configuration defines triggers for file changes and the actions to perform. ```bash npm install turbowatch cat > turbowatch.ts <<'EOD' import { defineConfig } from 'turbowatch'; export default defineConfig({ project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; }, }, ], }); EOD npm exec turbowatch ./turbowatch.ts ``` -------------------------------- ### Install Turbowatch Source: https://context7.com/gajus/turbowatch/llms.txt Use npm to install the package in your project. ```bash npm install turbowatch ``` -------------------------------- ### Turbowatch CLI Usage Examples Source: https://context7.com/gajus/turbowatch/llms.txt Provides various command-line interface examples for running Turbowatch, including using default and specific configuration files, glob patterns, and enabling logging. ```bash # Run with default turbowatch.ts in current directory npx turbowatch ``` ```bash # Run specific config file npx turbowatch ./turbowatch.ts ``` ```bash # Run multiple config files npx turbowatch ./foo.ts ./bar.ts ``` ```bash # Run with glob pattern npx turbowatch '**/turbowatch.ts' ``` ```bash # Enable logging (recommended) ROARR_LOG=true npx turbowatch | npx @roarr/cli ``` -------------------------------- ### watch Source: https://context7.com/gajus/turbowatch/llms.txt The main programmatic API for starting file watching operations. ```APIDOC ## watch ### Description The main programmatic API for starting file watching. Returns a `TurbowatchController` with a `shutdown` method for graceful termination. ### Parameters #### Request Body - **project** (string) - Required - Absolute path to the directory to watch. - **debounce** (object) - Optional - Configuration for debouncing file changes (default: { wait: 1000 }). - **triggers** (array) - Required - List of trigger configurations. ### Response - **shutdown** (function) - A method to perform graceful termination of the watch process. ``` -------------------------------- ### Watch Files Programmatically Source: https://context7.com/gajus/turbowatch/llms.txt Use the watch function to start file watching and receive a controller for graceful shutdown. ```typescript import { watch } from 'turbowatch'; const { shutdown } = await watch({ // Debounce file changes (default: 1000ms) debounce: { wait: 1000, }, // Absolute path to the directory to watch project: __dirname, triggers: [ { // Match TypeScript and TSX files, excluding node_modules expression: [ 'allof', ['not', ['dirname', 'node_modules']], [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.tsx', 'basename'], ], ], // Run on script startup (default: true) initialRun: true, // Abort current task when new changes detected (default: true) interruptible: true, // Unique trigger name name: 'build', // Handler executed on file changes onChange: async ({ spawn, files, first, attempt, abortSignal }) => { console.log(`Build triggered (attempt: ${attempt}, first: ${first})`); console.log(`Changed files: ${files.map(f => f.name).join(', ')}`); await spawn`tsc`; await spawn`tsc-alias`; }, // Cleanup on shutdown onTeardown: async ({ spawn }) => { await spawn`rm -fr ./dist`; }, // Retry configuration (default: { retries: 3 }) retry: { retries: 3, minTimeout: 1000, maxTimeout: 30000, factor: 2, }, }, ], }); // Handle graceful shutdown on SIGINT process.once('SIGINT', () => { void shutdown(); }); ``` -------------------------------- ### Example of throttled log output Source: https://github.com/gajus/turbowatch/blob/main/README.md This example demonstrates how Turbowatch throttles log output to prevent interleaved logs from multiple processes, making the output easier to read. To disable throttling, set `{ throttleOutput: { delay: 0 } }`. ```yaml redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 4.19MB / 9.60MB 22.3s api:dev: a1e4c6a7 > [18:48:37.171] 765ms debug @utilities #waitFor: Waiting for database to be ready... redis:dev: 973191cf > #5 sha256:d01ec855d06e16385fb33f299d9cc6eb303ea04378d0eea3a75d74e26c6e6bb9 0B / 1.39MB 22.7s api:dev: a1e4c6a7 > [18:48:37.225] 54ms debug @utilities #waitFor: Waiting for Redis to be ready... worker:dev: 2fb02d72 > [18:48:37.313] 88ms debug @utilities #waitFor: Waiting for database to be ready... redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 5.24MB / 9.60MB 22.9s worker:dev: 2fb02d72 > [18:48:37.408] 95ms debug @utilities #waitFor: Waiting for Redis to be ready... redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 6.29MB / 9.60MB 23.7s api:dev: a1e4c6a7 > [18:48:38.172] 764ms debug @utilities #waitFor: Waiting for database to be ready... api:dev: a1e4c6a7 > [18:48:38.227] 55ms debug @utilities #waitFor: Waiting for Redis to be ready... ``` ```yaml redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 4.19MB / 9.60MB 22.3s redis:dev: 973191cf > #5 sha256:d01ec855d06e16385fb33f299d9cc6eb303ea04378d0eea3a75d74e26c6e6bb9 0B / 1.39MB 22.7s redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 5.24MB / 9.60MB 22.9s redis:dev: 973191cf > #5 sha256:7f65636102fd1f499092cb075baa95784488c0bbc3e0abff2a6d853109e4a948 6.29MB / 9.60MB 23.7s api:dev: a1e4c6a7 > [18:48:37.171] 765ms debug @utilities #waitFor: Waiting for database to be ready... api:dev: a1e4c6a7 > [18:48:37.225] 54ms debug @utilities #waitFor: Waiting for Redis to be ready... api:dev: a1e4c6a7 > [18:48:38.172] 764ms debug @utilities #waitFor: Waiting for database to be ready... api:dev: a1e4c6a7 > [18:48:38.227] 55ms debug @utilities #waitFor: Waiting for Redis to be ready... worker:dev: 2fb02d72 > [18:48:37.313] 88ms debug @utilities #waitFor: Waiting for database to be ready... worker:dev: 2fb02d72 > [18:48:37.408] 95ms debug @utilities #waitFor: Waiting for Redis to be ready... ``` -------------------------------- ### Enable Turbowatch logging with Roarr Source: https://github.com/gajus/turbowatch/blob/main/README.md To enable log printing to stdout, export the `ROARR_LOG=true` environment variable. This example shows how to pipe Turbowatch output to `roarr` for pretty-printing. ```bash ROARR_LOG=true turbowatch | roarr ``` -------------------------------- ### Programmatic Shutdown of Turbowatch with AbortController Source: https://context7.com/gajus/turbowatch/llms.txt Shows how to use an AbortController to programmatically terminate Turbowatch. The spawned processes will receive a SIGTERM signal upon abortion. This example aborts the process after 10 seconds. ```typescript import { watch } from 'turbowatch'; const abortController = new AbortController(); void watch({ abortController, project: __dirname, triggers: [ { expression: ['match', '*', 'basename'], name: 'test', onChange: async ({ spawn }) => { // This process will receive SIGTERM when aborted await spawn`sleep 60`; }, }, ], }); // Abort after 10 seconds setTimeout(() => { abortController.abort(); }, 10_000); ``` -------------------------------- ### Watch node_modules with Turbowatch Source: https://github.com/gajus/turbowatch/blob/main/README.md Configure Turbowatch to watch the node_modules directory along with source and build directories. This setup assumes your project sources are in 'src' and build outputs to 'dist'. ```typescript import { watch } from 'turbowatch'; void watch({ project: path.resolve(__dirname, '../..'), triggers: [ { expression: [ 'anyof', [ 'allof', ['dirname', 'node_modules'], ['dirname', 'dist'], ['match', '*', 'basename'], ], [ 'allof', ['not', ['dirname', 'node_modules']], ['dirname', 'src'], ['match', '*', 'basename'], ], ], name: 'build', onChange: async ({ spawn }) => { return spawn`pnpm run build`; }, }, ], }); ``` -------------------------------- ### Reuse Turbowatch expressions and triggers Source: https://github.com/gajus/turbowatch/blob/main/README.md Abstract Turbowatch expressions and triggers into reusable functions. This example shows how to abstract an entire trigger configuration for use across multiple workspaces. ```typescript import { watch } from 'turbowatch'; import { buildTrigger, } from '@/turbowatch'; void watch({ project: __dirname, triggers: [ buildTrigger(), ], }); ``` -------------------------------- ### Using Specific File Watching Backends in Turbowatch Source: https://context7.com/gajus/turbowatch/llms.txt Demonstrates how to explicitly select a file watching backend like ChokidarWatcher or the smart TurboWatcher. Ensure necessary imports are included. ```typescript import { watch, TurboWatcher, // Smart watcher (auto-selects best backend) FSWatcher, // Native fs.watch (macOS Node.js v19.1+) ChokidarWatcher, // Chokidar-based watcher FileWatchingBackend, } from 'turbowatch'; // Use a specific backend void watch({ Watcher: ChokidarWatcher, project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; }, }, ], }); // Or use the smart TurboWatcher (default) void watch({ Watcher: TurboWatcher, project: __dirname, triggers: [], }); ``` -------------------------------- ### defineConfig Source: https://context7.com/gajus/turbowatch/llms.txt Creates a configuration object for the Turbowatch CLI. ```APIDOC ## defineConfig ### Description Creates a Turbowatch configuration object for use with the CLI. This is the recommended way to define your watch configuration when using the `turbowatch` executable. ### Request Body - **project** (string) - Required - Absolute path to the directory to watch. - **triggers** (array) - Required - List of trigger objects defining file matching and actions. ``` -------------------------------- ### Define Configuration Source: https://context7.com/gajus/turbowatch/llms.txt Use defineConfig to create a configuration object for the Turbowatch CLI. ```typescript import { defineConfig } from 'turbowatch'; export default defineConfig({ project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; }, }, ], }); ``` -------------------------------- ### Execute Commands with Spawn Source: https://context7.com/gajus/turbowatch/llms.txt The spawn function is a zx-bound utility for running shell commands. It supports sequential execution and complex shell syntax. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], name: 'build-and-test', onChange: async ({ spawn }) => { // Execute commands sequentially await spawn`tsc`; await spawn`tsc-alias`; // Run tests await spawn`npm test`; // Complex shell commands work too await spawn`rm -fr .dist && tsc --project tsconfig.build.json && rsync -cr --delete .dist/ ./dist/`; }, }, ], }); ``` -------------------------------- ### Execute Shell Commands with spawn Source: https://github.com/gajus/turbowatch/blob/main/README.md Use the `spawn` function to evaluate shell commands. This function is an instance of `zx` and abstracts it to enable graceful termination of child processes. ```typescript async ({ spawn }: ChangeEvent) => { await spawn`tsc`; await spawn`tsc-alias`; } ``` -------------------------------- ### Optimized build script for Turbowatch Source: https://github.com/gajus/turbowatch/blob/main/README.md An optimized build script that minimizes file change events by using an intermediate directory and rsync. This approach ensures at most one event is produced and avoids events if outputs haven't changed. ```bash rm -fr .dist && tsc --project tsconfig.build.json && rsync -cr --delete .dist/ ./dist/ && rm -fr .dist ``` -------------------------------- ### Configure Turbowatch with watch Source: https://github.com/gajus/turbowatch/blob/main/README.md Use the watch function to define project file watching behavior, including triggers, debouncing, and lifecycle routines like onChange and onTeardown. ```typescript import { watch, type ChangeEvent, } from 'turbowatch'; void watch({ // Debounces triggers by 1 second. // Most multi-file spanning changes are non-atomic. Therefore, it is typically desirable to // batch together information about multiple file changes that happened in short succession. // Provide { debounce: { wait: 0 } } to disable debounce. debounce: { wait: 1000, }, // The base directory under which all files are matched. // Note: This is different from the "root project" (https://github.com/gajus/turbowatch#project-root). project: __dirname, triggers: [ { // Expression match files based on name. // https://github.com/gajus/turbowatch#expressions expression: [ 'allof', ['not', ['dirname', 'node_modules']], [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.tsx', 'basename'], ] ], // Indicates whether the onChange routine should be triggered on script startup. // Defaults to true. Set it to false if you would like onChange routine to not run until the first changes are detected. initialRun: true, // Determines what to do if a new file change is detected while the trigger is executing. // If {interruptible: true}, then AbortSignal will abort the current onChange routine. // If {interruptible: false}, then Turbowatch will wait until the onChange routine completes. // Defaults to true. interruptible: false, // Name of the trigger. Used for debugging // Must match /^[a-z0-9-_]+$/ pattern and must be unique. name: 'build', // Routine that is executed when file changes are detected. onChange: async ({ spawn }: ChangeEvent) => { await spawn`tsc`; await spawn`tsc-alias`; }, // Routine that is executed when shutdown signal is received. onTeardown: async ({ spawn }) => { await spawn`rm -fr ./dist`; }, // Label a task as persistent if it is a long-running process, such as a dev server or --watch mode. persistent: false, // Retry a task if it fails. Otherwise, watch program will throw an error if trigger fails. // Defaults to { retries: 3 } retry: { retries: 3, }, }, ], }); ``` -------------------------------- ### Run multiple scripts with Turbowatch Source: https://github.com/gajus/turbowatch/blob/main/README.md Execute multiple scripts concurrently by passing their paths as arguments to the `turbowatch` command. Supports glob patterns for specifying multiple files. ```bash turbowatch ./foo.ts ./bar.ts ``` ```bash turbowatch '**/turbowatch.ts' ``` -------------------------------- ### Configure Turbowatch to use TurboWatcher Source: https://github.com/gajus/turbowatch/blob/main/README.md This TypeScript snippet shows how to configure Turbowatch to use the `TurboWatcher`, which automatically detects the best available file-watching backend. It imports necessary components from the 'turbowatch' library. ```typescript import { watch, // Smart Watcher that detects the best available file-watching backend. TurboWatcher, // fs.watch based file watcher. FSWatcher, // Chokidar based file watcher. ChokidarWatcher, // Interface that all file watchers must implement. FileWatchingBackend, } from 'turbowash'; export default watch({ Watcher: TurboWatcher, project: __dirname, triggers: [], }); ``` -------------------------------- ### Running Turborepo with Parallel Development Tasks Source: https://github.com/gajus/turbowatch/blob/main/README.md Execute Turborepo tasks in parallel using the `--parallel` flag. This is recommended when using Turbowatch for persistent development tasks. ```bash turbo run dev --parallel ``` -------------------------------- ### Restart Server on File Change Source: https://github.com/gajus/turbowatch/blob/main/README.md Configures Turbowatch to restart a server when `.ts` or `.graphql` files change. The `interruptible: true` setting ensures that spawned processes are killed on change detection. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: [ 'allof', ['not', ['dirname', 'node_modules']], [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.graphql', 'basename'], ] ], // Because of this setting, Turbowatch will kill the processes that spawn starts // when it detects changes when it detects a change. interruptible: true, name: 'start-server', onChange: async ({ spawn }) => { await spawn`tsx ./src/bin/wait.ts`; await spawn`tsx ./src/bin/server.ts`; }, }, ], }); ``` -------------------------------- ### Watch Next.js Development Server with Turbowatch Source: https://github.com/gajus/turbowatch/blob/main/README.md Wrap your Next.js development server in Turbowatch for consistent watch operations. This configuration ensures the dev server is not interrupted by file changes and runs persistently. ```typescript void watch({ project: __dirname, triggers: [ { expression: ['dirname', __dirname], // Marking this routine as non-interruptible will ensure that // next dev is not restarted when file changes are detected. interruptible: false, name: 'start-server', onChange: async ({ spawn }) => { await spawn`next dev`; }, // Enabling this option modifies what Turbowatch logs and warns // you if your configuration is incompatible with persistent tasks. persistent: true, }, ], }); ``` -------------------------------- ### Restart Server on File Changes Source: https://context7.com/gajus/turbowatch/llms.txt Use interruptible: true to kill and restart a process whenever a file change is detected. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: [ 'allof', ['not', ['dirname', 'node_modules']], [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.graphql', 'basename'], ], ], // Kill and restart on file changes interruptible: true, name: 'start-server', onChange: async ({ spawn }) => { // Wait for dependencies to be ready await spawn`tsx ./src/bin/wait.ts`; // Start the server await spawn`tsx ./src/bin/server.ts`; }, }, ], }); ``` -------------------------------- ### Turborepo Persistent Task Configuration Source: https://github.com/gajus/turbowatch/blob/main/README.md Configure a persistent task in Turborepo for development. This allows Turbowatch to be run in parallel with other Turborepo tasks. ```json "dev": { "cache": false, "persistent": true } ``` -------------------------------- ### Match *.ts or *.tsx Files Source: https://github.com/gajus/turbowatch/blob/main/README.md This expression uses `anyof` to match files that have either a `.ts` or `.tsx` extension, combining two `match` expressions. ```typescript [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.tsx', 'basename'] ] ``` -------------------------------- ### Execute project teardown tasks Source: https://github.com/gajus/turbowatch/blob/main/README.md Define an onTeardown callback within a trigger to perform cleanup operations when the Turbowatch process is terminated. ```ts import { watch } from 'turbowatch'; export default watch({ abortController, project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; }, onTeardown: async () => { await spawn`rm -fr ./dist`; }, }, ], }); ``` -------------------------------- ### Rebuild Assets on File Change Source: https://github.com/gajus/turbowatch/blob/main/README.md Configures Turbowatch to rebuild assets (TypeScript and aliases) when `.ts` files change, excluding files in `node_modules`. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: [ 'allof', ['not', ['dirname', 'node_modules']], ['match', '*.ts', 'basename'], ], name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; await spawn`tsc-alias`; }, }, ], }); ``` -------------------------------- ### Handling AbortSignal in Custom onChange Logic Source: https://context7.com/gajus/turbowatch/llms.txt Illustrates how to access and utilize the AbortSignal within an onChange handler for custom cancellation logic. It includes checking for pre-existing abort states and listening for abort events. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], interruptible: true, name: 'custom-task', onChange: async ({ abortSignal, spawn }) => { // Check if already aborted if (abortSignal?.aborted) { console.log('Task was aborted before starting'); return; } // Listen for abort events abortSignal?.addEventListener('abort', () => { console.log('Abort signal received, cleaning up...'); }, { once: true }); // spawn automatically handles abort signal await spawn`long-running-process`; }, }, ], }); ``` -------------------------------- ### Trigger Configuration Source: https://context7.com/gajus/turbowatch/llms.txt Defines the structure for individual triggers within a watch configuration. ```APIDOC ## Trigger Configuration ### Description Triggers define what files to watch and what actions to take when changes are detected. ### Parameters - **expression** (array) - Required - File matching expression. - **name** (string) - Required - Unique identifier for the trigger. - **onChange** (function) - Required - Handler executed on file changes. - **initialRun** (boolean) - Optional - Run on script startup (default: true). - **interruptible** (boolean) - Optional - Abort current task when new changes detected (default: true). - **onTeardown** (function) - Optional - Cleanup handler on shutdown. - **retry** (object) - Optional - Retry configuration (default: { retries: 3 }). - **hexColor** (string) - Optional - Custom hex color for log output. - **persistent** (boolean) - Optional - Mark as long-running process (default: false). ``` -------------------------------- ### Configure Triggers Source: https://context7.com/gajus/turbowatch/llms.txt Define trigger objects to specify file matching, task execution, and lifecycle hooks. ```typescript import { watch, type TriggerInput } from 'turbowatch'; const buildTrigger: TriggerInput = { // File matching expression expression: [ 'allof', ['not', ['dirname', 'node_modules']], ['match', '*.ts', 'basename'], ], // Custom hex color for log output hexColor: '#ff6b6b', // Run immediately on startup initialRun: true, // Allow interruption by new file changes interruptible: true, // Unique identifier for this trigger name: 'typescript-build', // Main handler function onChange: async ({ spawn, files, first, attempt, abortSignal, log, taskId }) => { log.info('Starting build task %s', taskId); await spawn`tsc --project tsconfig.build.json`; }, // Cleanup handler on shutdown onTeardown: async ({ spawn }) => { await spawn`rm -rf dist`; }, // Prefix output with trigger name (default: true) outputPrefix: true, // Mark as long-running process (default: false) persistent: false, // Retry on failure retry: { retries: 5 }, // Throttle output logging (default: { delay: 1000 }) throttleOutput: { delay: 500 }, }; void watch({ project: __dirname, triggers: [buildTrigger], }); ``` -------------------------------- ### Gracefully terminate Turbowatch using TurbowatchController Source: https://github.com/gajus/turbowatch/blob/main/README.md Use the shutdown method returned by the watch function to programmatically terminate the process and propagate SIGTERM to spawned children. ```ts const { shutdown } = await watch({ project: __dirname, triggers: [ { name: 'test', expression: ['match', '*', 'basename'], onChange: async ({ spawn }) => { // `sleep 60` will receive `SIGTERM` as soon as `shutdown()` is called. await spawn`sleep 60`; }, } ], }); // SIGINT is the signal sent when we press Ctrl+C process.once('SIGINT', () => { void shutdown(); }); ``` -------------------------------- ### Match All Files with *.ts Extension Source: https://github.com/gajus/turbowatch/blob/main/README.md This expression matches all files with a `.ts` extension using the `match` operator and `basename` qualifier. ```typescript ['match', '*.ts', 'basename'] ``` -------------------------------- ### Gracefully terminate Turbowatch using AbortController Source: https://github.com/gajus/turbowatch/blob/main/README.md Pass an AbortController instance to the watch configuration to trigger a shutdown by calling abort(). ```ts const abortController = new AbortController(); void watch({ abortController, project: __dirname, triggers: [ { name: 'test', expression: ['match', '*', 'basename'], onChange: async ({ spawn }) => { // `sleep 60` will receive `SIGTERM` as soon as `shutdown()` is called. await spawn`sleep 60`; }, } ], }); void abortController.abort(); ``` -------------------------------- ### Define File Matching Expressions Source: https://context7.com/gajus/turbowatch/llms.txt Use Watchman-compatible expressions to filter files. Expressions support logical operators like allof, anyof, and not, alongside glob patterns. ```typescript import { watch, type Expression } from 'turbowatch'; // Match all TypeScript files const matchTs: Expression = ['match', '*.ts', 'basename']; // Match files by full path const matchWholename: Expression = ['match', 'src/**/*.ts', 'wholename']; // Case-insensitive match const matchCaseInsensitive: Expression = ['imatch', '*.TS', 'basename']; // Match files in a specific directory const matchDirname: Expression = ['dirname', 'src']; // Case-insensitive dirname const matchIdirname: Expression = ['idirname', 'SRC']; // Combine with AND (all must match) const allOf: Expression = [ 'allof', ['not', ['dirname', 'node_modules']], ['match', '*.ts', 'basename'], ]; // Combine with OR (any must match) const anyOf: Expression = [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.tsx', 'basename'], ['match', '*.graphql', 'basename'], ]; // Negate an expression const notNodeModules: Expression = ['not', ['dirname', 'node_modules']]; // Complex expression: TS/TSX files outside node_modules const complexExpression: Expression = [ 'allof', ['not', ['dirname', 'node_modules']], ['not', ['dirname', '.git']], [ 'anyof', ['match', '*.ts', 'basename'], ['match', '*.tsx', 'basename'], ], ]; void watch({ project: __dirname, triggers: [ { expression: complexExpression, name: 'build', onChange: async ({ spawn }) => { await spawn`tsc`; }, }, ], }); ``` -------------------------------- ### Implement interruptible workflows with AbortSignal Source: https://github.com/gajus/turbowatch/blob/main/README.md Define an AbortSignal handler to manually manage process interruption when using custom scripts or external tools. ```ts import { type ProcessPromise } from 'zx'; const interrupt = async ( processPromise: ProcessPromise, abortSignal: AbortSignal, ) => { let aborted = false; const kill = () => { aborted = true; processPromise.kill(); }; abortSignal.addEventListener('abort', kill, { once: true }); try { await processPromise; } catch (error) { if (!aborted) { console.log(error); } } abortSignal.removeEventListener('abort', kill); }; ``` ```ts export default watch({ project: __dirname, triggers: [ { expression: ['match', '*.ts', 'basename'], interruptible: false, name: 'sleep', onChange: async ({ abortSignal }) => { await interrupt($`sleep 30`, abortSignal); }, }, ], }); ``` -------------------------------- ### Turbowatch Retry configuration type Source: https://github.com/gajus/turbowatch/blob/main/README.md Defines the configuration options for retrying failing triggers in Turbowatch. Includes properties for exponential backoff factor, maximum and minimum timeout between retries, and the maximum number of retries. ```typescript /** * @property factor The exponential factor to use. Default is 2. * @property maxTimeout The maximum number of milliseconds between two retries. Default is 30,000. * @property minTimeout The number of milliseconds before starting the first retry. Default is 1000. * @property retries The maximum amount of times to retry the operation. Default is 3. Seting this to 1 means do it once, then retry it once. */ type Retry = { factor?: number, maxTimeout?: number, minTimeout?: number, retries?: number, } ``` -------------------------------- ### Match *.ts Files Excluding index.ts Source: https://github.com/gajus/turbowatch/blob/main/README.md This expression uses `allof` and `not` to match all `.ts` files while excluding `index.ts`. ```typescript [ 'allof', ['match', '*.ts', 'basename'], [ 'not', ['match', 'index.ts', 'basename'] ] ] ``` -------------------------------- ### Watch node_modules in Monorepos Source: https://context7.com/gajus/turbowatch/llms.txt Monitor specific directories within node_modules, such as linked package dist folders, by combining path-based expressions. ```typescript import { watch } from 'turbowatch'; import path from 'node:path'; void watch({ // Watch from monorepo root project: path.resolve(__dirname, '../..'), triggers: [ { expression: [ 'anyof', // Watch dist folders in node_modules (linked packages) [ 'allof', ['dirname', 'node_modules'], ['dirname', 'dist'], ['match', '*', 'basename'], ], // Watch src folders outside node_modules [ 'allof', ['not', ['dirname', 'node_modules']], ['dirname', 'src'], ['match', '*', 'basename'], ], ], name: 'build', onChange: async ({ spawn }) => { return spawn`pnpm run build`; }, }, ], }); ``` -------------------------------- ### Manage Persistent Tasks Source: https://context7.com/gajus/turbowatch/llms.txt Mark tasks as persistent to ensure they auto-restart if they exit. Setting interruptible to false prevents the task from restarting on every file change. ```typescript import { watch } from 'turbowatch'; void watch({ project: __dirname, triggers: [ { expression: ['dirname', __dirname], // Non-interruptible ensures the server isn't restarted on every file change interruptible: false, name: 'dev-server', onChange: async ({ spawn }) => { // Start Next.js dev server await spawn`next dev`; }, // Mark as persistent - will auto-restart if it exits persistent: true, }, ], }); ``` -------------------------------- ### Turbowatch Expression Type Definition Source: https://github.com/gajus/turbowatch/blob/main/README.md Defines the structure of Turbowatch expressions, including logical operators like `allof`, `anyof`, `not`, and matching operators like `dirname` and `match`. ```typescript type Expression = // Evaluates as true if all of the grouped expressions also evaluated as true. | ['allof', ...Expression[]] // Evaluates as true if any of the grouped expressions also evaluated as true. | ['anyof', ...Expression[]] // Evaluates as true if a given file has a matching parent directory. | ['dirname' | 'idirname', string] // Evaluates as true if a glob matches against the basename of the file. | ['match' | 'imatch', string, 'basename' | 'wholename'] // Evaluates as true if the sub-expression evaluated as false, i.e. inverts the sub-expression. | ['not', Expression]; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.