Skip to content

Commit

Permalink
cli: fix --watch reload for built files
Browse files Browse the repository at this point in the history
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 <ruyadorno@google.com>
  • Loading branch information
ruyadorno committed Oct 31, 2022
1 parent 548f505 commit df6b0cd
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
1 change: 0 additions & 1 deletion lib/internal/main/watch_mode.js
Expand Up @@ -93,7 +93,6 @@ function reportGracefulTermination() {
}

async function stop() {
watcher.clearFileFilters();
const clearGraceReport = reportGracefulTermination();
await killAndWait();
clearGraceReport();
Expand Down
38 changes: 37 additions & 1 deletion test/sequential/test-watch-mode.mjs
Expand Up @@ -6,9 +6,10 @@ import path from 'node:path';
import { execPath } from 'node:process';
import { describe, it } from 'node:test';
import { spawn } from 'node:child_process';
import { writeFileSync, readFileSync } from 'node:fs';
import { writeFileSync, rmSync, readFileSync } from 'node:fs';
import { inspect } from 'node:util';
import { once } from 'node:events';
import { setTimeout } from 'node:timers/promises';

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

it('should watch changes to previously loaded dependencies', async () => {
const dependencyContent = 'module.exports = {}';
const dependency = createTmpFile(dependencyContent);
const relativeDependencyPath = `./${path.basename(dependency)}`;
const dependant = createTmpFile(`console.log(require('${relativeDependencyPath}'))`);

let stderr = '';
let stdout = '';
const child = spawn(execPath, ['--watch', '--no-warnings', dependant], { encoding: 'utf8' });
child.stdout.on('data', (data) => { stdout += data; });
child.stderr.on('data', (data) => { stderr += data; });
child.on('error', (err) => { throw err; });

await once(child.stdout, 'data');
rmSync(dependency, { force: true });

await setTimeout(600); // throttle + 100
writeFileSync(dependency, dependencyContent);

await setTimeout(600); // throttle + 100
child.kill();
await once(child, 'exit');

// TODO(ruyadorno): fs.watch is flaky when removing files from a watched
// folder, in this test we want to assert the expected reload happened
// after a missing file is recreated so we'll skip the assertions in case
// the expected reload+failure never happened.
// This should be an assertion for the failure instead of an if block once
// the source of this flakyness gets resolved.
if (stdout.match(/Failed/g)?.length) {
assert.strictEqual(stdout.split('Failed')[1].match(/Restarting/g)?.length, 1, new Error('should have restarted after fail'));
assert.ok(stderr.match(/MODULE_NOT_FOUND/g)?.length, new Error('should have failed for not finding the removed file'));
}
});

it('should restart multiple times', async () => {
const file = createTmpFile();
const { stderr, stdout } = await spawnWithRestarts({ file, restarts: 3 });
Expand Down

0 comments on commit df6b0cd

Please sign in to comment.