From bb649d43ab1535ba1b1434dd68f059a87f68a1e9 Mon Sep 17 00:00:00 2001 From: marcopiraccini Date: Sat, 7 Mar 2026 06:51:38 +0100 Subject: [PATCH] watch: strip watch flags from NODE_OPTIONS in child process Signed-off-by: marcopiraccini --- lib/internal/main/watch_mode.js | 28 ++++++++++++++++++++++++ test/sequential/test-watch-mode.mjs | 33 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/lib/internal/main/watch_mode.js b/lib/internal/main/watch_mode.js index 06c2c8602da444..6340bcda9460ae 100644 --- a/lib/internal/main/watch_mode.js +++ b/lib/internal/main/watch_mode.js @@ -7,6 +7,7 @@ const { ArrayPrototypePush, ArrayPrototypePushApply, ArrayPrototypeSlice, + RegExpPrototypeSymbolSplit, StringPrototypeStartsWith, } = primordials; @@ -84,6 +85,32 @@ for (let i = 0; i < process.execArgv.length; i++) { ArrayPrototypePushApply(argsWithoutWatchOptions, kCommand); +const kNodeOptions = process.env.NODE_OPTIONS; +let cleanNodeOptions = kNodeOptions; +if (kNodeOptions != null) { + const nodeOptionsArgs = []; + const parts = RegExpPrototypeSymbolSplit(/\s+/, kNodeOptions); + for (let i = 0; i < parts.length; i++) { + const part = parts[i]; + if (part === '') continue; + if (part === '--watch' || + part === '--watch-preserve-output' || + StringPrototypeStartsWith(part, '--watch=') || + StringPrototypeStartsWith(part, '--watch-preserve-output=') || + StringPrototypeStartsWith(part, '--watch-path=') || + StringPrototypeStartsWith(part, '--watch-kill-signal=')) { + continue; + } + if (part === '--watch-path' || part === '--watch-kill-signal') { + // These flags take a separate value argument + i++; + continue; + } + ArrayPrototypePush(nodeOptionsArgs, part); + } + cleanNodeOptions = ArrayPrototypeJoin(nodeOptionsArgs, ' '); +} + const watcher = new FilesWatcher({ debounce: 200, mode: kShouldFilterModules ? 'filter' : 'all' }); ArrayPrototypeForEach(kWatchedPaths, (p) => watcher.watchPath(p)); @@ -99,6 +126,7 @@ function start() { env: { ...process.env, WATCH_REPORT_DEPENDENCIES: '1', + NODE_OPTIONS: cleanNodeOptions, }, }); watcher.watchChildProcessModules(child); diff --git a/test/sequential/test-watch-mode.mjs b/test/sequential/test-watch-mode.mjs index a5cac129ad1c21..fa2fb323565218 100644 --- a/test/sequential/test-watch-mode.mjs +++ b/test/sequential/test-watch-mode.mjs @@ -922,4 +922,37 @@ process.on('message', (message) => { await done(); } }); + + it('should strip all watch flags from NODE_OPTIONS in child process', async () => { + const file = createTmpFile('console.log(process.env.NODE_OPTIONS);'); + const nodeOptions = [ + '--watch', // bare boolean + '--watch=true', // boolean with =value + '--watch-path=./src', // string with =value + '--watch-path', './test', // String with space-separated value + '--watch-preserve-output', // bare boolean + '--watch-preserve-output=true', // boolean with =value + '--watch-kill-signal=SIGKILL', // string with =value + '--watch-kill-signal', 'SIGINT', // String with space-separated value + '--max-old-space-size=4096', + '--no-warnings', + ].join(' '); + const { done, restart } = runInBackground({ + args: ['--watch', file], + options: { + env: { ...process.env, NODE_OPTIONS: nodeOptions }, + }, + }); + + try { + const { stdout, stderr } = await restart(); + + assert.strictEqual(stderr, ''); + const nodeOptionsLine = stdout.find((line) => line.includes('--max-old-space-size')); + assert.ok(nodeOptionsLine); + assert.strictEqual(nodeOptionsLine, '--max-old-space-size=4096 --no-warnings'); + } finally { + await done(); + } + }); });