diff --git a/packages/cli/schemas/lerna-schema.json b/packages/cli/schemas/lerna-schema.json index 307cce5fa..71f970e02 100644 --- a/packages/cli/schemas/lerna-schema.json +++ b/packages/cli/schemas/lerna-schema.json @@ -1386,7 +1386,7 @@ } }, "watch": { - "emitChangesDelay": { + "debounce": { "type": "number", "description": "Defaults to 200, time to wait in milliseconds before emitting all the file changes into a single event." }, diff --git a/packages/cli/src/cli-commands/cli-watch-commands.ts b/packages/cli/src/cli-commands/cli-watch-commands.ts index b27d38744..77a0654e4 100644 --- a/packages/cli/src/cli-commands/cli-watch-commands.ts +++ b/packages/cli/src/cli-commands/cli-watch-commands.ts @@ -34,7 +34,7 @@ export default { hidden: true, type: 'boolean', }, - 'emit-changes-delay': { + debounce: { group: 'Command Options:', describe: 'Time to wait in milliseconds before emitting all the file changes into a single event, defaults to 200', diff --git a/packages/core/src/models/command-options.ts b/packages/core/src/models/command-options.ts index 56252f7ce..ede54c064 100644 --- a/packages/core/src/models/command-options.ts +++ b/packages/core/src/models/command-options.ts @@ -432,7 +432,7 @@ export interface WatchCommandOption { * This provide enough time for the system to collect all Chokidar events (1x per file changes) * and merge them into a single Lerna watch change event to be emitted (Lerna will join all file paths into a CSV string separated by whitespace by default). */ - emitChangesDelay?: number; + debounce?: number; /** Defaults to whitespace, the delimiter that will be used to separate files when mutiple file changes are emitted by the watch */ fileDelimiter?: string; diff --git a/packages/watch/README.md b/packages/watch/README.md index 1bdcf89af..dd765c6d1 100644 --- a/packages/watch/README.md +++ b/packages/watch/README.md @@ -25,6 +25,7 @@ lerna watch ```sh $ lerna watch -- +# you can press "x" to exit the watch mode. ``` The values `$LERNA_PACKAGE_NAME` and `$LERNA_FILE_CHANGES` will be replaced with the package name, the file that changed respectively. If multiple file changes are detected, they will all be listed and separated by a whitespace (unless custom file delimiter are provided). @@ -106,7 +107,7 @@ $ npx -c 'lerna watch -- echo \$LERNA_PACKAGE_NAME \$LERNA_FILE_CHANGES' - [`@lerna/watch`](#lernawatch) - [Usage](#usage) - [Options](#options) - - [`--emit-changes-delay`](#--emit-changes-delay) + - [`--debounce`](#--debounce) - [`--file-delimiter`](#--file-delimiter) - [`--glob`](#--glob) - [`--stream`](#--stream) @@ -128,11 +129,11 @@ $ npx -c 'lerna watch -- echo \$LERNA_PACKAGE_NAME \$LERNA_FILE_CHANGES' > **Note** to limit the number of files being watched, you might want to take a look at either [`--ignored`](#--ignored) and/or [`--glob`](#--glob) options. The `lerna watch` command skips `.git/`, `dist/` and `node_modules/` directories by default. -### `--emit-changes-delay` -Defaults to `200`, time to wait in milliseconds before collecting all file changes before emitting them into a single watch event. This option exists because we want to provide enough time for `lerna watch` to collect all file changes (within that period) and merge these file paths into a single watch change event (chokidar has no grouping feature and emits an event for every file that changed) and we want to avoid emitting too many events (especially for a watch that triggers a rebuild). This option will come into play when you make a code change that triggers hundred of file changes, you might need to adjust the delay by increasing its value (for comparison sake the `Nx` library have their `Nx Watch` set, and fixed, at `500`). +### `--debounce` +Defaults to `200` time to wait in milliseconds before collecting all file changes before emitting them into a single watch event. Basically this option is to provide enough time for `lerna watch` to collect all files that changed (within that period) and avoid emitting too many watch events since Chokidar has no such debounce feature. This option becomes quite important when you do code change that affects hundred of file changes at the same time, the default is 200 but you might need to adjust the delay by increasing its value (in comparison, many libraries use `500` debounce for a watch). ```sh -$ lerna watch --emit-changes-delay=500 -- +$ lerna watch --debounce=500 -- ``` ### `--file-delimiter` diff --git a/packages/watch/src/__tests__/watch-command.spec.ts b/packages/watch/src/__tests__/watch-command.spec.ts index d21fd18a3..fe6ac182f 100644 --- a/packages/watch/src/__tests__/watch-command.spec.ts +++ b/packages/watch/src/__tests__/watch-command.spec.ts @@ -154,7 +154,7 @@ describe('Watch Command', () => { }); it('should take glob input option, without slash prefix, and expect it to be appended to the file path being watch by chokidar', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--glob', 'src/**/*.{ts,tsx}', '--', 'lerna run build'); + await lernaWatch(testDir)('--debounce', '0', '--glob', 'src/**/*.{ts,tsx}', '--', 'lerna run build'); expect(watchMock).toHaveBeenCalledWith( [ @@ -171,7 +171,7 @@ describe('Watch Command', () => { }); it('should take glob input option, with slash prefix, and expect same appended to the file path being watch by chokidar', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--glob', '/src/**/*.{ts,tsx}', '--', 'lerna run build'); + await lernaWatch(testDir)('--debounce', '0', '--glob', '/src/**/*.{ts,tsx}', '--', 'lerna run build'); expect(watchMock).toHaveBeenCalledWith( [ @@ -188,7 +188,7 @@ describe('Watch Command', () => { }); it('should be able to take --await-write-finish options as a boolean', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--await-write-finish', '--', 'lerna run build'); + await lernaWatch(testDir)('--debounce', '0', '--await-write-finish', '--', 'lerna run build'); expect(watchMock).toHaveBeenCalledWith( [path.join(testDir, 'packages/package-1'), path.join(testDir, 'packages/package-2')], @@ -203,7 +203,7 @@ describe('Watch Command', () => { }); it('should take options prefixed with "awf" (awfPollInterval) and transform them into a valid chokidar "awaitWriteFinish" option', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--awf-poll-interval', '500', '--', 'lerna run build'); + await lernaWatch(testDir)('--debounce', '0', '--awf-poll-interval', '500', '--', 'lerna run build'); expect(watchMock).toHaveBeenCalledWith( [path.join(testDir, 'packages/package-1'), path.join(testDir, 'packages/package-2')], @@ -218,14 +218,7 @@ describe('Watch Command', () => { }); it('should take options prefixed with "awf" (awfStabilityThreshold) and transform them into a valid chokidar "awaitWriteFinish" option', async () => { - await lernaWatch(testDir)( - '--emit-changes-delay', - '0', - '--awf-stability-threshold', - '275', - '--', - 'lerna run build' - ); + await lernaWatch(testDir)('--debounce', '0', '--awf-stability-threshold', '275', '--', 'lerna run build'); expect(watchMock).toHaveBeenCalledWith( [path.join(testDir, 'packages/package-1'), path.join(testDir, 'packages/package-2')], @@ -240,7 +233,7 @@ describe('Watch Command', () => { }); it('should execute change watch callback only in the given scope', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); await watchChangeHandler('change', path.join(testDir, 'packages/package-2/some-file.ts')); expect(calledInPackages()).toEqual(['package-2']); @@ -262,7 +255,7 @@ describe('Watch Command', () => { it('should execute change watch callback with --stream in the given scope', async () => { await lernaWatch(testDir)( - '--emit-changes-delay', + '--debounce', '0', '--scope', 'package-2', @@ -297,7 +290,7 @@ describe('Watch Command', () => { }); it('should execute change watch callback with default whitespace file delimiter', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--', 'echo $LERNA_PACKAGE_NAME $LERNA_FILE_CHANGES'); + await lernaWatch(testDir)('--debounce', '0', '--', 'echo $LERNA_PACKAGE_NAME $LERNA_FILE_CHANGES'); watchChangeHandler('change', path.join(testDir, 'packages/package-2/file-1.ts')); await watchChangeHandler('change', path.join(testDir, 'packages/package-2/some-file.ts')); @@ -323,7 +316,7 @@ describe('Watch Command', () => { it('should execute change watch callback with custom file delimiter when defined', async () => { // prettier-ignore - await lernaWatch(testDir)('--emit-changes-delay', '0', '--file-delimiter', ';;', '--', 'echo $LERNA_PACKAGE_NAME $LERNA_FILE_CHANGES'); + await lernaWatch(testDir)('--debounce', '0', '--file-delimiter', ';;', '--', 'echo $LERNA_PACKAGE_NAME $LERNA_FILE_CHANGES'); watchChangeHandler('change', path.join(testDir, 'packages/package-2/file-1.ts')); await watchChangeHandler('change', path.join(testDir, 'packages/package-2/some-file.ts')); @@ -348,7 +341,7 @@ describe('Watch Command', () => { }); it('should execute watch add callback only on the given scope', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); await watchAddHandler('add', path.join(testDir, 'packages/package-2/some-file.ts')); expect(calledInPackages()).toEqual(['package-2']); @@ -369,7 +362,7 @@ describe('Watch Command', () => { }); it('should execute watch add callback only the given scope', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); await watchAddDirHandler('addDir', path.join(testDir, 'packages/package-2/some-folder')); expect(calledInPackages()).toEqual(['package-2']); @@ -390,7 +383,7 @@ describe('Watch Command', () => { }); it('should execute watch add callback only the given scope', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); await watchUnlinkHandler('unlink', path.join(testDir, 'packages/package-2/some-file.ts')); expect(calledInPackages()).toEqual(['package-2']); @@ -411,7 +404,7 @@ describe('Watch Command', () => { }); it('should execute watch add callback only the given scope', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); await watchUnlinkDirHandler('unlinkDir', path.join(testDir, 'packages/package-2/some-folder')); expect(calledInPackages()).toEqual(['package-2']); @@ -432,7 +425,7 @@ describe('Watch Command', () => { }); it('should execute watch callback only the given scoped package', async () => { - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); watchAddHandler('add', path.join(testDir, 'packages/package-1/my-file.ts')); watchAddHandler('add', path.join(testDir, 'packages/package-2/new-file-1.ts')); @@ -462,7 +455,7 @@ describe('Watch Command', () => { it('should execute watch multiple callbacks that were queued on multiple packages', async () => { // prettier-ignore - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-{1,2}', '--', 'echo $LERNA_PACKAGE_NAME && Promise.resolve(true)'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-{1,2}', '--', 'echo $LERNA_PACKAGE_NAME && Promise.resolve(true)'); watchAddHandler('add', path.join(testDir, 'packages/package-2/new-file-1.ts')); watchUnlinkHandler('unlink', path.join(testDir, 'packages/package-2/new-file-1.ts')); @@ -514,7 +507,7 @@ describe('Watch Command', () => { try { // prettier-ignore - await lernaWatch(testDir)('--emit-changes-delay', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); + await lernaWatch(testDir)('--debounce', '0', '--scope', 'package-2', '--', 'echo $LERNA_PACKAGE_NAME'); const promise = watchAddHandler('add', path.join(testDir, 'packages/package-2/some-file.ts')); stdin.send('x'); stdin.end(); diff --git a/packages/watch/src/constants.ts b/packages/watch/src/constants.ts index f74128bde..749cd62c9 100644 --- a/packages/watch/src/constants.ts +++ b/packages/watch/src/constants.ts @@ -19,4 +19,4 @@ export const CHOKIDAR_AVAILABLE_OPTIONS = [ export const FILE_DELIMITER = ' '; // threshold to hold before firing a single event with merged files -export const EMIT_CHANGES_DELAY = 200; +export const DEBOUNCE_DELAY = 200; diff --git a/packages/watch/src/watch-command.ts b/packages/watch/src/watch-command.ts index 5bfd97fe0..daf4870cf 100644 --- a/packages/watch/src/watch-command.ts +++ b/packages/watch/src/watch-command.ts @@ -12,7 +12,7 @@ import { FilterOptions, getFilteredPackages } from '@lerna-lite/filter-packages' import chokidar from 'chokidar'; import path from 'path'; -import { CHOKIDAR_AVAILABLE_OPTIONS, EMIT_CHANGES_DELAY, FILE_DELIMITER } from './constants'; +import { CHOKIDAR_AVAILABLE_OPTIONS, DEBOUNCE_DELAY, FILE_DELIMITER } from './constants'; import { ChangesStructure } from './models'; export function factory(argv: WatchCommandOption) { @@ -155,7 +155,7 @@ export class WatchCommand extends Command { } protected executeCommandCallback() { - const debounceDelay = this.options.emitChangesDelay ?? EMIT_CHANGES_DELAY; + const debounceDelay = this.options.debounce ?? DEBOUNCE_DELAY; return new Promise((resolve) => { // once we reached emit change stability threshold, we'll fire events for each packages & events while the file paths array will be merged