Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/internal/watch_mode/files_watcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,9 @@ class FilesWatcher extends EventEmitter {
if (ArrayIsArray(message['watch:import'])) {
ArrayPrototypeForEach(message['watch:import'], (file) => this.filterFile(fileURLToPath(file), key));
}
if (ArrayIsArray(message['watch:worker'])) {
ArrayPrototypeForEach(message['watch:worker'], (file) => this.filterFile(file, key));
}
} catch {
// Failed watching file. ignore
}
Expand Down
16 changes: 16 additions & 0 deletions lib/internal/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,17 @@ class HeapProfileHandle {
}
}

/**
* Tell the watch mode that a worker file was instantiated.
* @param {string} filename Absolute path of the worker file
* @returns {void}
*/
function reportWorkerToWatchMode(filename) {
if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) {
process.send({ 'watch:worker': [filename] });
}
}

class Worker extends EventEmitter {
constructor(filename, options = kEmptyObject) {
throwIfBuildingSnapshot('Creating workers');
Expand Down Expand Up @@ -275,6 +286,11 @@ class Worker extends EventEmitter {
name = StringPrototypeTrim(options.name);
}

// Report to watch mode if this is a regular file (not eval, internal, or data URL)
if (!isInternal && doEval === false) {
reportWorkerToWatchMode(filename);
}

debug('instantiating Worker.', `url: ${url}`, `doEval: ${doEval}`);
// Set up the C++ handle for the worker, as well as some internal wiring.
this[kHandle] = new WorkerImpl(url,
Expand Down
67 changes: 67 additions & 0 deletions test/parallel/test-watch-mode-worker.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import { Worker } from 'node:worker_threads';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { writeFileSync, unlinkSync } from 'node:fs';

describe('watch:worker event system', () => {
it('should report worker files to parent process', async () => {
const testDir = tmpdir();
const workerFile = join(testDir, `test-worker-${Date.now()}.js`);

try {
// Create a simple worker that reports itself
writeFileSync(workerFile, `
const { Worker } = require('node:worker_threads');
module.exports = { test: true };
`);

// Create a worker that requires the file
const worker = new Worker(workerFile);

await new Promise((resolve) => {
worker.on('online', () => {
worker.terminate();
resolve();
});
});
} finally {
try { unlinkSync(workerFile); } catch {}
}
});

it('should not report eval workers', (t, done) => {
// Eval workers should be filtered out
// This is a unit test that validates the condition logic
const isInternal = false;
const doEval = true;

// Condition: !isInternal && doEval === false
const shouldReport = !isInternal && doEval === false;
assert.strictEqual(shouldReport, false, 'Eval workers should not be reported');
done();
});

it('should not report internal workers', (t, done) => {
// Internal workers should be filtered out
const isInternal = true;
const doEval = false;

// Condition: !isInternal && doEval === false
const shouldReport = !isInternal && doEval === false;
assert.strictEqual(shouldReport, false, 'Internal workers should not be reported');
done();
});

it('should report regular workers', (t, done) => {
// Regular workers should be reported
const isInternal = false;
const doEval = false;

// Condition: !isInternal && doEval === false
const shouldReport = !isInternal && doEval === false;
assert.strictEqual(shouldReport, true, 'Regular workers should be reported');
done();
});
});