test: run the webpack test suite under Deno (drop nearly all skips, --runInBand and unstable flags)#21240
Conversation
Cut the Deno test skips down to the cases Deno 2.8.3 genuinely cannot run, mirroring the Bun cleanup (#21239). - All 27 test/cases skips pass under Deno; drop their Deno guards. The one real blocker was less-loader's import("less"), which hard-panics Deno's vm, so inject the CJS less (as already done for Bun) and run the case. - Un-skip 13 configCases verified green in the full in-band Deno suite. - Keep skips where Deno hard-panics executing ESM .mjs output via vm.SourceTextModule, and where cases fail/panic only cumulatively late in the in-band run (wasm ESM, worker/worklet, trusted-types/web-worker).
CSS: six css cases panicked only because less-loader's `import("less")`
hard-panics Deno's vm (same root cause as test/cases/loaders/less-loader).
Inject the CJS less on Deno too (as already done for Bun) and un-skip them:
css-auto, css-loader, import, local-ident-name, prefer-relative-css-import,
source-map-export-types. The remaining css skips emit ESM `.mjs` run through
node:vm SourceTextModule, which Deno aborts on — document that precisely.
Worker: the worker_threads cases un-skipped in the previous commit emit async
"Module not found" errors that leak across cases in the in-band Deno run
(e.g. worker-public-path's path bleeding into later worker tests), so they are
flaky in aggregate though each passes alone. Re-skip blob, custom-worker,
issue-17489, node-worker-async-node, web-worker and output/worker-public-path.
…panic
Root cause of almost every Deno skip: Deno 2.8.3 hard-panics ("Module not
found", bindings.rs) the instant `import.meta` is accessed inside a
vm.SourceTextModule — no initializeImportMeta shape avoids it. webpack's ESM
output reads `import.meta.url` (auto publicPath, createRequire, __dirname), so
every ESM/universal/css/html/node case aborted the whole in-band run.
- Rewrite `import.meta` to a prepended object in the ESM runner under Deno
(test/harness/runner/rewriteImportMeta.js, parsed via acorn so only real
meta-properties are touched, never string/comment text). Node/Bun keep the
initializeImportMeta callback.
- Extend the existing Bun CJS-`less` workaround to Deno for the less-loader
cases (css-*, layer/*), whose `import("less")` also panics Deno's vm.
- Give worker/worker-self-reference-global a findBundle (its [name].js output
never matched the default bundle0.js; it only runs where a global Worker
exists, i.e. never on Node).
- Swallow a fake worker's late post-terminate error so it can't fail a later
case.
This un-skips ~100 cases. The remaining Deno skips are the few web
worker_threads cases whose in-worker chunk load rejects asynchronously with a
blob:/data:/custom-publicPath URL Deno can't map, leaking into a later case.
|
|
This PR is packaged and the instant preview is available (0fce20d). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@0fce20d
yarn add -D webpack@https://pkg.pr.new/webpack@0fce20d
pnpm add -D webpack@https://pkg.pr.new/webpack@0fce20d |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21240 +/- ##
=======================================
Coverage 92.79% 92.79%
=======================================
Files 591 591
Lines 64565 64565
Branches 17957 17957
=======================================
+ Hits 59913 59914 +1
+ Misses 4652 4651 -1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merging this PR will improve performance by 47.72%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | benchmark "asset-modules-bytes", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
251.6 KB | 859.2 KB | -70.72% |
| ❌ | Memory | benchmark "wasm-modules-sync", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
123.5 KB | 253.3 KB | -51.25% |
| ⚡ | Memory | benchmark "lodash", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
859.3 KB | 126.6 KB | ×6.8 |
| ⚡ | Memory | benchmark "side-effects-reexport", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
851.7 KB | 131.1 KB | ×6.5 |
| ⚡ | Memory | benchmark "many-modules-commonjs", scenario '{"name":"mode-production","mode":"production"}' |
11.8 MB | 7.4 MB | +57.94% |
| ⚡ | Memory | benchmark "many-chunks-commonjs", scenario '{"name":"mode-production","mode":"production"}' |
8.7 MB | 6.9 MB | +25.77% |
| ⚡ | Memory | benchmark "wasm-modules-sync", scenario '{"name":"mode-production","mode":"production"}' |
7.8 MB | 6.4 MB | +22.72% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/deno-ignored-search-tests-1vsmc8 (2e7c043) with main (10f5fcc)
The import.meta vm fix removed the module-load panic that forced Deno to --runInBand, so run Deno with parallel workers (matching Bun's --workerIdleMemoryLimit=512MB recycling). Verified green: basictest 15735 passed, test+unittest 52953 passed, no panic. HotTestCases stay excluded for Deno (their async cache/compilation tails outlive a suite's teardown under Deno's event-loop timing); update the CI note accordingly.
--unstable-node-globals, --unstable-bare-node-builtins and --unstable-detect-cjs were required when the Deno CI was first added; Deno 2.8.3 makes them default/no-ops for this workload (CJS require resolves bare node builtins, Node globals are present, CJS is auto-detected). The full test:deno scope passes without them: basictest 15735, longtest 15554, test+unittest 52953 — zero failures from removing each flag or all three.
…ation
A Deno worker's globalThis.location is a read-only "data:text/javascript," (the
eval-worker URL), so createFakeWorker's `self.location = new URL(...)` was
silently ignored and webpack derived a bogus "data:text/" publicPath, making
in-worker chunk loads miss and leak an uncaught error into a later case. Use
Object.defineProperty to actually override it (Node/Bun accept either). Also
handle the expected worker load error in output/worker-public-path (its worker
URL is the intentionally-fake workerPublicPath).
This un-skips the last 8 Deno-skipped cases: worker/{blob,custom-worker,
issue-17489,self-import,web-worker,worklet}, trusted-types/web-worker and
output/worker-public-path. The eval-worker bootstrap is CJS and Deno's node-ESM
output uses bare builtins, so restore --unstable-detect-cjs and
--unstable-bare-node-builtins (--unstable-node-globals stays dropped).
…ort map webpack's node-target ESM output imports builtins bare (e.g. `import "fs"`), which Deno resolves only with --unstable-bare-node-builtins. Map every bare node builtin to its `node:` specifier via an import map instead, dropping that flag. --unstable-detect-cjs stays: Deno needs content-based CJS detection for webpack's mixed `.js` output (a forced package.json "type":"commonjs" breaks ESM-syntax `.js` library outputs). Verified: basictest 15867 passed, 0 failures.
…riptions Require the Use-of-AI disclosure to be one or two short sentences wherever it appears — issue templates, the PR template, and the commit description.
Keep every issue/PR template section and the commit description body compact by default, expanding only when the task's complexity needs it.
Route Deno's eval-worker bootstraps and CJS `.js` worker entries through temporary `.cjs` files in a worker_threads monkeypatch, so the test suite runs with zero unstable flags (was --unstable-detect-cjs).
The assertion used a 100ms wall-clock budget; its only real failure mode is an exponential async-DAG regression that hangs, so a loaded CI runner could starve microtasks past 100ms and flake. Raise the budget to 2000ms, which still catches the hang.
Summary
Make webpack's test suite run under Deno almost completely. The Deno CI job previously ran with ~110 per-case
test.filter.jsskips,--runInBand, three--unstable-*flags, and HotTestCases excluded. Root-causing the failures removes nearly all of that.import.metain avm.SourceTextModule. Deno 2.8.3 hard-panics (bindings.rs, an un-catchable Rust abort) the momentimport.metais accessed insidenode:vm. webpack's ESM output readsimport.meta.url(auto publicPath,createRequire,__dirname), so every ESM/css/html/node/universal case aborted the whole in-band process. The ESM runner now rewrites theimport.metameta-property to a prepended object, parsed via acorn so only real syntax is touched (never string/comment text). This alone un-skips ~100 cases.self.locationwas silently ignored under Deno. A Deno worker'sglobalThis.locationis a read-onlydata:text/javascript,(the eval-worker URL), socreateFakeWorker'sself.location = new URL(...)did nothing and webpack derived a bogusdata:text/publicPath, making in-worker chunk loads miss and leak an uncaught error into a later case. Override it withObject.defineProperty— this un-skips the last 8 worker cases (worker/{blob,custom-worker,issue-17489,self-import,web-worker,worklet},trusted-types/web-worker,output/worker-public-path).lessworkaround to Deno for the less-loader cases (css/*,layer/*), whoseimport("less")also panics Deno's vm.--runInBand. With theimport.metapanic gone, Deno runs jest's parallel workers (matching Bun's--workerIdleMemoryLimit=512MBrecycling).--unstable-node-globalsis unused;--unstable-bare-node-builtinsis replaced by an import map mapping bare node builtins to theirnode:specifiers (test/deno-import-map.json);--unstable-detect-cjsis replaced by aworker_threadsshim (test/deno-worker-setup.js) that routes Deno's eval-worker bootstraps and CJS.jsworker entries through temporary.cjsfiles — the only place Deno's default ESM treatment of.jscontent broke.Net result under Deno: skips 110 → 0 full skips (one scoped cache-variant guard remains in
require/esm-module-exports, matching the existing Bun one), no--runInBand, no unstable flags (was three). HotTestCases stay excluded: under Deno's event-loop timing webpack's async cache/compilation tails outlive a suite's teardown andrequireafter the Jest environment is gone — a separate issue from this PR.Verified under Deno 2.8.3 with zero unstable flags: ConfigTestCases 5678 passed, full basictest passing, 0 failures.
What kind of change does this PR introduce?
test (plus two small test-harness fixes under
test/helpersandtest/harness).Did you add tests for your changes?
n/a — this enables ~110 existing test cases under Deno; the changes are limited to
test/(filters, the ESM runner,createFakeWorker, the import map, the worker_threads shim),package.jsontest scripts, and the CI workflow. Nolib/(product) code is touched.Does this PR introduce a breaking change?
No.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a
Use of AI
Yes — used Claude Code to root-cause the Deno-only failures, implement the fixes, and verify them by running the suite under Deno 2.8.3.