Skip to content

worker: add support for Web Workers - #64894

Open
avivkeller wants to merge 3 commits into
nodejs:mainfrom
avivkeller:web-workers
Open

worker: add support for Web Workers#64894
avivkeller wants to merge 3 commits into
nodejs:mainfrom
avivkeller:web-workers

Conversation

@avivkeller

Copy link
Copy Markdown
Member

Fixes: #43583

Adds support for the Web Worker API as defined by the HTML Standard:
https://html.spec.whatwg.org/multipage/workers.html

The implementation trys to follow the specification as close as Node.js allows, so note the following differences:

  • SharedWorker is not implemented. Its lifetime and sharing model depend on origins and browsing contexts, concepts that do not exist in Node.js.

  • Worker scripts are loaded synchronously from the local filesystem rather than fetched over the network. As a result:

    • new Worker() and importScripts() accept only file:, data:, and blob: URLs.
    • Any other scheme throws a NotSupportedError.
    • An unreadable script throws a NetworkError.
    • Redirects, nosniff, and HTTP MIME type validation are not applicable. MIME type validation is performed only for data: and blob: URLs.
    • WorkerOptions.credentials is validated for API compatibility but otherwise has no effect, since no network request is made.
  • Node.js has no origin model. Consequently, concepts such as same-origin and cross-origin do not exist, and location.origin is null for file: workers.

  • close() terminates the worker immediately instead of following the specification's "closing flag" algorithm. Code remaining in the current task after close() is therefore not executed.

  • The worker global is the normal Node.js global object with DedicatedWorkerGlobalScope inserted into its prototype chain rather than the inverse (a fresh global created from the interface). Additionally, classic file: workers are executed through the CommonJS/ESM loaders rather than as classic scripts, so top-level declarations do not become global properties. Classic data: and blob: workers continue to execute as classic scripts.

  • ErrorEvents dispatched to Worker instances include message and error, but not filename, lineno, or colno. Unhandled worker errors are also not propagated further. These are a result of the worker_threads implementation that is underneath the web workers implemantion.

  • The following WorkerGlobalScope events are never dispatched:

    • languagechange, online, and offline, since these concepts do not exist in Node.js.
    • rejectionhandled and unhandledrejection, since Node.js exposes equivalent process-level events but does not implement the PromiseRejectionEvent interface or the per-rejection preventDefault() behavior required by the HTML Standard.
  • On the main thread, relative worker script URLs are resolved against the current working directory because there is no document base URL. Within a worker, relative URLs resolve against the worker's own URL, matching the specification.

AI Disclaimer: I used slight AI help to resolve issues that came up during me validating the WPT tests.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/loaders
  • @nodejs/startup
  • @nodejs/web-standards

@nodejs-github-bot nodejs-github-bot added lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Aug 1, 2026
@avivkeller

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member Author

I'm not sure if I should break the WPT additions into their own commit / PR for ease of reviewing?

You should be able to collapse the test folder to view the lib impl changes

Finally, I haven't added dedicated tests for this outside of the WPT, which should cover it.

@avivkeller avivkeller added worker Issues and PRs related to Worker support. web-standards Issues and PRs related to Web APIs semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment thread lib/internal/webworker.js
Comment on lines +112 to +129
const kJavaScriptMIMETypes = new SafeSet([
'application/ecmascript',
'application/javascript',
'application/x-ecmascript',
'application/x-javascript',
'text/ecmascript',
'text/javascript',
'text/javascript1.0',
'text/javascript1.1',
'text/javascript1.2',
'text/javascript1.3',
'text/javascript1.4',
'text/javascript1.5',
'text/jscript',
'text/livescript',
'text/x-ecmascript',
'text/x-javascript',
]);

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Undici keeps this map internally, but does not expose it, fwiw

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wrapper is because the WPT tests import assuming they are running on a server (e.g. /absolute/path/to/import), so I rewrite them as relative.

@avivkeller avivkeller added commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

jasnell commented Aug 1, 2026

Copy link
Copy Markdown
Member

The web platform tests in this PR really ought to be separated out into a separate commit to make reviewing this easier. 1300+ files changes with 54k+ lines changed is very difficult to review in a single commit.

Comment thread doc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
Member Author

The web platform tests in this PR really ought to be separated out into a separate commit to make reviewing this easier. 1300+ files changes with 54k+ lines changed is very difficult to review in a single commit.

Broken up! c73f2fe has the actual changes

@codecov

codecov Bot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 88.57432% with 113 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.15%. Comparing base (8a1ca0f) to head (5f5e95d).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
lib/internal/webworker.js 86.99% 113 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64894      +/-   ##
==========================================
+ Coverage   90.14%   90.15%   +0.01%     
==========================================
  Files         746      747       +1     
  Lines      242849   243813     +964     
  Branches    45771    45867      +96     
==========================================
+ Hits       218906   219805     +899     
- Misses      15438    15500      +62     
- Partials     8505     8508       +3     
Files with missing lines Coverage Δ
lib/internal/blob.js 90.26% <100.00%> (+0.39%) ⬆️
...internal/bootstrap/web/exposed-window-or-worker.js 93.89% <100.00%> (+0.09%) ⬆️
lib/internal/encoding.js 96.66% <100.00%> (+0.04%) ⬆️
lib/internal/event_target.js 99.19% <100.00%> (+<0.01%) ⬆️
lib/internal/main/worker_thread.js 94.58% <100.00%> (+0.23%) ⬆️
lib/internal/modules/helpers.js 98.92% <100.00%> (-0.01%) ⬇️
lib/internal/navigator.js 98.78% <100.00%> (+<0.01%) ⬆️
lib/internal/process/pre_execution.js 97.03% <100.00%> (-0.93%) ⬇️
lib/internal/webidl.js 99.46% <100.00%> (+0.01%) ⬆️
lib/internal/worker.js 96.76% <100.00%> (+0.01%) ⬆️
... and 5 more

... and 39 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please revert this file change:

Refs: #63938
Refs: nodejs/node-core-utils#1094
Refs: nodejs/node-core-utils#1082

@mcollina

mcollina commented Aug 1, 2026

Copy link
Copy Markdown
Member

This is gargantuan. Can you add a review guide and/or split into chunks?

Comment on lines +71 to +88
"modules/resources/dynamic-import-remote-origin-credentials-checker-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},
"modules/resources/dynamic-import-remote-origin-referrer-checker-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},
"modules/resources/dynamic-import-remote-origin-script-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},
"modules/resources/static-import-remote-origin-credentials-checker-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},
"modules/resources/static-import-remote-origin-referrer-checker-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},
"modules/resources/static-import-remote-origin-script-worker.sub.js": {
"skip": "Not a test file; used as a worker script by other tests"
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this apply to all *.sub.js as a convention? See Wildcard patterns in file names

Comment thread doc/api/globals.md
* For `blob:` URLs, the script must be held in memory, so blobs backed by a file,
such as those returned by [`fs.openAsBlob()`][], cannot be used.

### Differences from the HTML Standard

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, I haven't added dedicated tests for this outside of the WPT, which should cover it.

I believe that for all limitations or differences you document there should be dedicated tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. experimental Issues and PRs related to experimental features. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. semver-minor PRs that contain new features and should be released in the next minor version. web-standards Issues and PRs related to Web APIs worker Issues and PRs related to Worker support.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

5 participants