Skip to content

Commit df6b0cd

Browse files
committed
cli: fix --watch reload for built files
When watching folders that contain files that result from a build step, e.g: TypeScript output, stored template result, etc. The watcher will not reload the application in case one of these resulting files gets regenerated, given that when these files are removed they're no longer tracked by the watcher. This changeset enables reloading the app when changing files that result from a build step by removing the reset of the tracked filtered files on every reload. Fixing the ability to watch and reload the app when a previously-known output file is changed. Signed-off-by: Ruy Adorno <[email protected]>
1 parent 548f505 commit df6b0cd

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

lib/internal/main/watch_mode.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ function reportGracefulTermination() {
9393
}
9494

9595
async function stop() {
96-
watcher.clearFileFilters();
9796
const clearGraceReport = reportGracefulTermination();
9897
await killAndWait();
9998
clearGraceReport();

test/sequential/test-watch-mode.mjs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import path from 'node:path';
66
import { execPath } from 'node:process';
77
import { describe, it } from 'node:test';
88
import { spawn } from 'node:child_process';
9-
import { writeFileSync, readFileSync } from 'node:fs';
9+
import { writeFileSync, rmSync, readFileSync } from 'node:fs';
1010
import { inspect } from 'node:util';
1111
import { once } from 'node:events';
12+
import { setTimeout } from 'node:timers/promises';
1213

1314
if (common.isIBMi)
1415
common.skip('IBMi does not support `fs.watch()`');
@@ -174,6 +175,41 @@ describe('watch mode', { concurrency: true, timeout: 60_0000 }, () => {
174175
});
175176
});
176177

178+
it('should watch changes to previously loaded dependencies', async () => {
179+
const dependencyContent = 'module.exports = {}';
180+
const dependency = createTmpFile(dependencyContent);
181+
const relativeDependencyPath = `./${path.basename(dependency)}`;
182+
const dependant = createTmpFile(`console.log(require('${relativeDependencyPath}'))`);
183+
184+
let stderr = '';
185+
let stdout = '';
186+
const child = spawn(execPath, ['--watch', '--no-warnings', dependant], { encoding: 'utf8' });
187+
child.stdout.on('data', (data) => { stdout += data; });
188+
child.stderr.on('data', (data) => { stderr += data; });
189+
child.on('error', (err) => { throw err; });
190+
191+
await once(child.stdout, 'data');
192+
rmSync(dependency, { force: true });
193+
194+
await setTimeout(600); // throttle + 100
195+
writeFileSync(dependency, dependencyContent);
196+
197+
await setTimeout(600); // throttle + 100
198+
child.kill();
199+
await once(child, 'exit');
200+
201+
// TODO(ruyadorno): fs.watch is flaky when removing files from a watched
202+
// folder, in this test we want to assert the expected reload happened
203+
// after a missing file is recreated so we'll skip the assertions in case
204+
// the expected reload+failure never happened.
205+
// This should be an assertion for the failure instead of an if block once
206+
// the source of this flakyness gets resolved.
207+
if (stdout.match(/Failed/g)?.length) {
208+
assert.strictEqual(stdout.split('Failed')[1].match(/Restarting/g)?.length, 1, new Error('should have restarted after fail'));
209+
assert.ok(stderr.match(/MODULE_NOT_FOUND/g)?.length, new Error('should have failed for not finding the removed file'));
210+
}
211+
});
212+
177213
it('should restart multiple times', async () => {
178214
const file = createTmpFile();
179215
const { stderr, stdout } = await spawnWithRestarts({ file, restarts: 3 });

0 commit comments

Comments
 (0)