Skip to content

Commit

Permalink
fix(watch): use a better debounce option name for the watch (#476)
Browse files Browse the repository at this point in the history
* fix(watch): use a better debounce option name for the watch
  • Loading branch information
ghiscoding authored Feb 4, 2023
1 parent 79ab643 commit eb0bbc1
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/cli/schemas/lerna-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
},
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/cli-commands/cli-watch-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/models/command-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 5 additions & 4 deletions packages/watch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ lerna watch

```sh
$ lerna watch -- <command>
# 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).
Expand Down Expand Up @@ -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)
Expand All @@ -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 -- <command>
$ lerna watch --debounce=500 -- <command>
```

### `--file-delimiter`
Expand Down
39 changes: 16 additions & 23 deletions packages/watch/src/__tests__/watch-command.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
Expand All @@ -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(
[
Expand All @@ -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')],
Expand All @@ -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')],
Expand All @@ -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')],
Expand All @@ -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']);
Expand All @@ -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',
Expand Down Expand Up @@ -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'));

Expand All @@ -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'));

Expand All @@ -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']);
Expand All @@ -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']);
Expand All @@ -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']);
Expand All @@ -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']);
Expand All @@ -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'));
Expand Down Expand Up @@ -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'));
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion packages/watch/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
4 changes: 2 additions & 2 deletions packages/watch/src/watch-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -155,7 +155,7 @@ export class WatchCommand extends Command<WatchCommandOption & FilterOptions> {
}

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
Expand Down

0 comments on commit eb0bbc1

Please sign in to comment.