worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

worker: add support for Web Workers - #64894

Closed
avivkeller wants to merge 6 commits into
nodejs:mainfrom
avivkeller:web-workers
Closed

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

Conversation

@avivkeller

@avivkelleravivkeller commented Aug 1, 2026

Copy link
Copy Markdown
Member

Closes: #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 (per the spec, this is emitted as an error event).
    • 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.

TODO before merge:

  • test WPT Report upload against staging.wpt.fyi with @panva

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

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

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

avivkeller commented Aug 1, 2026

Copy link
Copy Markdown
MemberAuthor

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.

@avivkelleravivkeller added worker Issues and PRs related to the worker_threads module and Worker API. web-standards Issues and PRs related to web-platform APIs and standards compliance. semver-minor PRs that contain new features and should be released in the next minor version. labels Aug 1, 2026
Comment threadlib/internal/webworker.js
Comment threadtest/common/wpt/webworker.js
@avivkelleravivkeller added commit-queue-squash PRs the Commit Queue should land as one squashed commit. experimental Issues and PRs related to experimental features. labels Aug 1, 2026
@jasnell

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 threaddoc/api/globals.md Outdated
@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

codecovBot commented Aug 1, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.63799% with 71 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.13%. Comparing base (91a99c5) to head (1beb0ab).
⚠️ Report is 20 commits behind head on main.

Files with missing linesPatch %Lines
lib/internal/webworker.js92.70%71 Missing ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #64894 +/- ##
==========================================
- Coverage 90.32% 90.13% -0.19% 
==========================================
Files 751 752 +1 Lines 250000 251424 +1424 Branches 47231 47247 +16 ==========================================
+ Hits 225816 226628 +812 - Misses 15566 16162 +596 - Partials 8618 8634 +16 
Files with missing linesCoverage Δ
lib/internal/blob.js89.40% <100.00%> (-0.46%)⬇️
...internal/bootstrap/web/exposed-window-or-worker.js91.60% <100.00%> (-2.20%)⬇️
lib/internal/encoding.js96.66% <100.00%> (+0.04%)⬆️
lib/internal/event_target.js98.78% <100.00%> (-0.40%)⬇️
lib/internal/main/worker_thread.js94.91% <100.00%> (+0.55%)⬆️
lib/internal/modules/helpers.js98.92% <100.00%> (-0.01%)⬇️
lib/internal/navigator.js98.78% <100.00%> (+<0.01%)⬆️
lib/internal/process/pre_execution.js97.14% <100.00%> (-0.58%)⬇️
lib/internal/webidl.js99.12% <100.00%> (-0.34%)⬇️
lib/internal/worker.js96.76% <100.00%> (+0.01%)⬆️
... and 5 more

... and 57 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.

Comment threadtest/fixtures/wpt/README.md
@mcollina

Copy link
Copy Markdown
Member

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

Comment threadtest/wpt/status/workers.json Outdated
Comment threaddoc/api/globals.md
@panva

panva commented Aug 1, 2026

Copy link
Copy Markdown
Member

I have:

  • added a commit to accomodate multi-global WPT tests in the runner and reporter
  • added a TODO to the description when this stabilizes to test the daily WPT Report upload against staging.wpt.fyi

@avivkeller

Copy link
Copy Markdown
MemberAuthor

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

It's only extremely large due to the added WPT tests. You can make it easier to review by

  1. Not reviewing the WPT test commit (the second commit in the PR), or
  2. Collapsing the test/fixtures folder in the GitHub UI

Comment threadtest/parallel/test-worker-spec-differences.js Outdated
Comment threadlib/internal/webworker.js Outdated
Signed-off-by: Aviv Keller <me@aviv.sh>
@panva

Copy link
Copy Markdown
Member

rebased and squashed, i made no functional changes

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@panvapanva removed the commit-queue-failed PRs whose Commit Queue landing failed and need manual intervention before retrying. label Aug 14, 2026
@avivkelleravivkeller added request-ci Add this label to start a Jenkins CI on a PR. and removed request-ci Add this label to start a Jenkins CI on a PR. labels Aug 15, 2026
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
avivkeller added a commit that referenced this pull request Aug 15, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
@avivkeller

Copy link
Copy Markdown
MemberAuthor

Landed in c7b962c...c73d0b1

@panva

panva commented Aug 16, 2026

Copy link
Copy Markdown
Member

@avivkeller please follow up with a 27.x semver major flag flip. --no-experimental-* to turn off, on by default, still experimental active development.

lazerg added a commit to lazerg/node that referenced this pull request Aug 23, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in nodejs#64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: nodejs#65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
nodejs-github-bot pushed a commit that referenced this pull request Aug 27, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@jimmywarting

Copy link
Copy Markdown

I see that there are some issues with supporting async, file-backed Blobs.

I wonder if this could be handled by separating the Worker’s creation from the loading of its script:

  1. Create a MessageChannel first.
  2. Create the Worker object without loading the script yet.
  3. Return the Worker to the developer immediately.
  4. The developer can now call postMessage() as usual. Those messages can be queued/deferred until the worker’s side is ready to consume them.
  5. Load the worker script asynchronously, including cases where loading the script involves async operations such as fs.openAsBlob().
  6. Once the script has finished loading, connect the other end of the MessageChannel and start consuming the queued messages.

This would effectively decouple the synchronous construction of the Worker from the asynchronous loading/initialization of its script, while preserving the existing postMessage() API semantics.

The MessageChannel would act as the buffer between the developer-facing Worker object and the worker runtime until the script is ready.

aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
To hopefully get to the bottom of WPT crashes that have no traces.
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Co-authored-by: Aviv Keller <me@aviv.sh>
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
Signed-off-by: Aviv Keller <me@aviv.sh>
PR-URL: #64894Fixes: #43583
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 29, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Sep 3, 2026
removeEventListener(type, fn, true) never matched a listener added
the same way, because removeEventListener compared
options?.capture === true directly while addEventListener flattened
a boolean third argument via validateEventListenerOptions().
The underlying fix landed independently in #64894 (worker:
add support for Web Workers), as a side effect of an unrelated
refactor, so this PR now only adds the regression test that would
have caught it. WPT does not cover this path: the
EventTarget-removeEventListener.any.js test is skipped in
test/wpt/status/dom/events.json.
Fixes: #65244
Signed-off-by: Lazizbek Ergashev <lazerg2@gmail.com>
PR-URL: #65245
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.commit-queue-rebasePRs the Commit Queue should land as multiple self-contained commits.experimentalIssues and PRs related to experimental features.lib / srcIssues and PRs involving general changes in the lib/ or src/ directories.needs-ciPRs that need a full CI run.review wantedPRs that need review.semver-minorPRs that contain new features and should be released in the next minor version.web-standardsIssues and PRs related to web-platform APIs and standards compliance.workerIssues and PRs related to the worker_threads module and Worker API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Web Workers

11 participants

@avivkeller@nodejs-github-bot@jasnell@mcollina@panva@nikelborm@jimmywarting@legendecas@aduh95@KhafraDev@Archkon