Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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();
});
});