diff --git a/README.md b/README.md index 7af1fdb72..7788dafa7 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,13 @@ tsx watch ./file.ts All imported files are watched except from the following directories: `node_modules`, `bower_components`, `vendor`, `dist`, and `.*` (hidden directories). +#### Ignore files from watch + +To exclude files from being watched, pass in a path or glob to the `--ignore` flag: +```sh +tsx watch --ignore ./ignore-me.js --ignore ./ignore-me-too.js ./file.ts +``` + #### Tips - Press Return to manually rerun - Pass in `--clear-screen=false` to disable clearing the screen on rerun diff --git a/src/watch/index.ts b/src/watch/index.ts index aaba93ba8..3eb2504e0 100644 --- a/src/watch/index.ts +++ b/src/watch/index.ts @@ -27,7 +27,11 @@ const flags = { description: 'Clearing the screen on rerun', default: true, }, -}; + ignore: { + type: [String], + description: 'Paths & globs to exclude from being watched', + }, +} as const; export const watchCommand = command({ name: 'watch', @@ -47,6 +51,7 @@ export const watchCommand = command({ noCache: argv.flags.noCache, tsconfigPath: argv.flags.tsconfig, clearScreen: argv.flags.clearScreen, + ignore: argv.flags.ignore, ipc: true, }; @@ -123,6 +128,8 @@ export const watchCommand = command({ // Distribution files '**/dist/**', + + ...options.ignore, ], ignorePermissionErrors: true, }, diff --git a/tests/specs/watch.ts b/tests/specs/watch.ts index 6d83f7d39..fe2022501 100644 --- a/tests/specs/watch.ts +++ b/tests/specs/watch.ts @@ -1,4 +1,5 @@ import path from 'path'; +import { setTimeout } from 'timers/promises'; import { testSuite, expect } from 'manten'; import { createFixture } from 'fs-fixture'; import { tsx } from '../utils/tsx'; @@ -141,5 +142,58 @@ export default testSuite(async ({ describe }, fixturePath: string) => { // await tsxProcess; // }, 2000); }); + + describe('ignore', ({ test }) => { + test('file path & glob', async () => { + const entryFile = 'index.js'; + const fileA = 'file-a.js'; + const fileB = 'directory/file-b.js'; + let value = Date.now(); + + const fixture = await createFixture({ + [entryFile]: ` + import valueA from './${fileA}' + import valueB from './${fileB}' + console.log(valueA, valueB) + `.trim(), + [fileA]: `export default ${value}`, + [fileB]: `export default ${value}`, + }); + + const tsxProcess = tsx({ + args: [ + 'watch', + '--clear-screen=false', + `--ignore=${path.join(fixture.path, fileA)}`, + `--ignore=${path.join(fixture.path, 'directory/*')}`, + path.join(fixture.path, entryFile), + ], + }); + + tsxProcess.stdout!.on('data', async (data: Buffer) => { + const chunkString = data.toString(); + if (chunkString === `${value} ${value}\n`) { + value = Date.now(); + await Promise.all([ + fixture.writeFile(fileA, `export default ${value}`), + fixture.writeFile(fileB, `export default ${value}`), + ]); + + await setTimeout(500); + await fixture.writeFile(entryFile, 'console.log("TERMINATE")'); + } + + if (chunkString === 'TERMINATE\n') { + tsxProcess.kill(); + } + }); + + const tsxProcessResolved = await tsxProcess; + await fixture.rm(); + + expect(tsxProcessResolved.stdout).not.toMatch(`${value} ${value}`); + expect(tsxProcessResolved.stderr).toBe(''); + }, 5000); + }); }); });