Skip to content

test: run the webpack test suite under Deno (drop nearly all skips, --runInBand and unstable flags)#21240

Merged
alexander-akait merged 12 commits into
mainfrom
claude/deno-ignored-search-tests-1vsmc8
Jun 22, 2026
Merged

test: run the webpack test suite under Deno (drop nearly all skips, --runInBand and unstable flags)#21240
alexander-akait merged 12 commits into
mainfrom
claude/deno-ignored-search-tests-1vsmc8

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Jun 22, 2026

Copy link
Copy Markdown
Member

Summary

Make webpack's test suite run under Deno almost completely. The Deno CI job previously ran with ~110 per-case test.filter.js skips, --runInBand, three --unstable-* flags, and HotTestCases excluded. Root-causing the failures removes nearly all of that.

  • The dominant blocker was import.meta in a vm.SourceTextModule. Deno 2.8.3 hard-panics (bindings.rs, an un-catchable Rust abort) the moment import.meta is accessed inside node:vm. webpack's ESM output reads import.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 the import.meta meta-property to a prepended object, parsed via acorn so only real syntax is touched (never string/comment text). This alone un-skips ~100 cases.
  • Worker self.location was silently ignored under Deno. A Deno worker's globalThis.location is a read-only data:text/javascript, (the eval-worker URL), so createFakeWorker's self.location = new URL(...) did nothing and webpack derived a bogus data:text/ publicPath, making in-worker chunk loads miss and leak an uncaught error into a later case. Override it with Object.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).
  • Extend the existing Bun CJS-less workaround to Deno for the less-loader cases (css/*, layer/*), whose import("less") also panics Deno's vm.
  • Drop --runInBand. With the import.meta panic gone, Deno runs jest's parallel workers (matching Bun's --workerIdleMemoryLimit=512MB recycling).
  • Drop all three unstable flags. --unstable-node-globals is unused; --unstable-bare-node-builtins is replaced by an import map mapping bare node builtins to their node: specifiers (test/deno-import-map.json); --unstable-detect-cjs is replaced by a worker_threads shim (test/deno-worker-setup.js) that routes Deno's eval-worker bootstraps and CJS .js worker entries through temporary .cjs files — the only place Deno's default ESM treatment of .js content 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 and require after 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/helpers and test/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.json test scripts, and the CI workflow. No lib/ (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.

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.
@changeset-bot

changeset-bot Bot commented Jun 22, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 2e7c043

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions

github-actions Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (0fce20d).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@0fce20d
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@0fce20d
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@0fce20d

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.79%. Comparing base (10f5fcc) to head (2e7c043).

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     
Flag Coverage Δ
css-parsing 28.68% <ø> (ø)
html5lib 31.13% <ø> (ø)
integration 88.71% <ø> (+<0.01%) ⬆️
test262 45.41% <ø> (-0.01%) ⬇️
unit 41.28% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 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.

@codspeed-hq

codspeed-hq Bot commented Jun 22, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 47.72%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 5 improved benchmarks
❌ 2 regressed benchmarks
✅ 137 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

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)

Open in CodSpeed

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.
@alexander-akait alexander-akait changed the title test: un-skip Deno tests that pass; keep only genuinely-unrunnable skips test: run the webpack test suite under Deno (drop nearly all skips, --runInBand and unstable flags) Jun 22, 2026
…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.
@github-actions

Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging claude/deno-ignored-search-tests-1vsmc8 into main will be
99.35%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.77%100%100%98.77%91
examples
   build-common.js100%100%100%100%
   buildAll.js100%100%100%100%
   examples.js100%100%100%100%
   template-common.js98.21%100%100%98.21%72
examples/custom-javascript-parser
   test.filter.js100%100%100%100%
examples/custom-javascript-parser/internals
   acorn-parse.js100%100%100%100%
   meriyah-parse.js100%100%100%100%
   oxc-parse.js91.30%100%100%91.30%140, 142–143, 145, 147, 153–154, 161, 168, 90
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/typescript
   test.filter.js100%100%100%100%
examples/typescript-non-erasable
   test.filter.js50%100%100%50%5
examples/virtual-modules
   test.filter.js100%100%100%100%
examples/wasm-bindgen-esm
   test.filter.js100%100%100%100%
examples/wasm-complex
   test.filter.js100%100%100%100%
examples/wasm-emscripten
   test.filter.js100%100%100%100%
examples/wasm-simple
   test.filter.js100%100%100%100%
examples/wasm-simple-source-phase
   test.filter.js100%100%100%100%
lib
   APIPlugin.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%101
   CacheFacade.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%39
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CleanPlugin.js99.15%100%100%99.15%207, 227
   CodeGenerationResults.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.43%100%100%98.43%1618, 1937, 1944, 1952, 1974, 1977, 2917, 3396–3397, 3429, 4095, 4125, 4178–4179, 4183, 4188, 4204–4205, 4219–4220, 4225–4226, 4703, 4729, 514, 519, 5537, 5569, 5586, 5602, 5618, 5633, 5658–5659, 5661, 5989, 5994, 6000, 6003, 6015, 6017, 6021, 6037, 6052, 6084, 6138, 6162, 6276, 764–765
   Compiler.js99.56%100%100%99.56%1139–1140, 1148
   ConcatenationScope.js98.59%100%100%98.59%189
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js100%100%100%100%
   ContextModuleFactory.js97.40%100%100%97.40%258, 395, 418, 420, 424, 433–434
   ContextReplacementPlugin.js100%100%100%100%
   DefinePlugin.js99%100%100%99%171–172, 188, 207, 281
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.50%100%100%98.50%471, 517
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DotenvPlugin.js98.41%100%100%98.41%378, 391–392
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%49
   ErrorHelpers.js100%100%100%100%
   EvalDevToolModulePlugin.js100%100%100%100%
   EvalSourceMapDevToolPlugin.js100%100%100%100%
   ExportsInfo.js100%100%100%100%
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.50%100%100%98.50%1057, 1060, 445–449, 451, 597
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FileSystemInfo.js99.52%100%100%99.52%182, 2354–2355, 2358, 2369, 2380, 2391, 278, 3795, 3810, 3834
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.46%100%100%98.46%425, 434, 436, 440
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LazyBarrel.js100%100%100%100%
   LibraryTemplatePlugin.js100%100%100%100%
   LoaderOptionsPlugin.js100%100%100%100%
   LoaderTargetPlugin.js100%100%100%100%
   MainTemplate.js100%100%100%100%
   ManifestPlugin.js100%100%100%100%
   Module.js98.50%100%100%98.50%1285, 1290, 1350, 1364, 1426, 1435
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%106, 108
   ModuleGraph.js99.73%100%100%99.73%1005
   ModuleGraphConnection.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   MultiCompiler.js99.69%100%100%99.69%659
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.90%100%100%97.90%1237, 1240, 1257, 1274, 1521, 1555, 1571, 1658, 2014, 2313, 2318–2328, 418, 422, 576
   NormalModuleFactory.js99.47%100%100%99.47%1083, 1392, 486, 498
   NormalModuleReplacementPlugin.js100%100%100%100%
   NullFactory.js100%100%100%100%
   OptimizationStages.js100%100%100%100%
   OptionsApply.js100%100%100%100%
   Parser.js100%100%100%100%
   PlatformPlugin.js100%100%100%100%
   PrefetchPlugin.js100%100%100%100%
   ProgressPlugin.js98.85%100%100%98.85%519–520, 525, 527, 591
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   ResolverFactory.js100%100%100%100%
   RuntimeGlobals.js100%100%100%100%
   RuntimeModule.js100%100%100%100%
   RuntimePlugin.js100%100%100%100%
   RuntimeTemplate.js100%100%100%100%
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js98.62%100%100%98.62%220, 224, 226, 419, 430, 891
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js99.17%100%100%99.17%176–177
   UseStrictPlugin.js100%100%100%100%
   WarnCaseSensitiveModulesPlugin.js100%100%100%100%
   WarnDeprecatedOptionPlugin.js100%100%100%100%
   WarnNoModeSetPlugin.js100%100%100%100%
   WatchIgnorePlugin.js100%100%100%100%
   Watching.js100%100%100%100%
   WebpackError.js100%100%100%100%
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%371
   cli.js98.62%100%100%98.62%10, 119, 545, 577, 627, 897
   index.js99.72%100%100%99.72%184
   validateSchema.js94.67%100%100%94.67%100, 87, 89, 98
   webpack.js96.33%100%100%96.33%10, 198, 220, 222
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModule.js100%100%100%100%
   AssetModulesPlugin.js97.32%100%100%97.32%281, 305, 308, 36, 360, 41
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%71, 83, 91
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%106, 113–114, 122, 89
   PackFileCacheStrategy.js96.40%100%100%96.40%1250, 1350, 1354, 1416, 628, 647, 657–659, 661, 677–678, 683, 686, 688, 693, 698, 722, 728, 762, 768, 774, 779, 790, 799, 804–805, 807, 824, 830–831, 833
   ResolverCachePlugin.js100%100%100%100%
   getLazyHashedEtag.js100%100%100%100%
   mergeEtags.js100%100%100%100%
lib/config
   browserslistTargetHandler.js100%100%100%100%
   defaults.js99.31%100%100%99.31%1444–1446, 1454, 274, 277, 282, 286
   defineConfig.js100%100%100%100%
   normalization.js99.02%100%100%99.02%191–192, 258, 273
 

@alexander-akait alexander-akait merged commit 0fce20d into main Jun 22, 2026
68 checks passed
@alexander-akait alexander-akait deleted the claude/deno-ignored-search-tests-1vsmc8 branch June 22, 2026 11:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant