fix: track CommonJS build dependencies without require.cache children; run more suites on Bun/Deno - #21531
Conversation
… visibly The BinaryMiddleware "newer V8 format version" case built its fixture with v8.serialize, whose wire format differs on Bun, so it silently returned. The guard it covers is pure byte logic, so build the payload by hand and derive the version from the runtime's own v8.serialize(null)[1] — it now runs on Node, Deno and Bun instead of being skipped. For cases that need a capability a runtime lacks (a launchable Chrome for the ProfilingPlugin/WebpackDevServer suites, require(esm) for LoaderRunner), convert the silent early-return into it.skip so they report as skipped rather than falsely passing.
…platforms Both cases were filtered out on Deno, Bun and Node < 24.9 because they loaded ESM-only @babel/core@8, which cannot load under Jest's vm there. Drop the babel dependency so the cases run everywhere: - dynamic-import: replace JSX (@babel/preset-react) with React.createElement so webpack parses the sources natively; the case still exercises vendor splitting and the pages/[request] dynamic-import chunk name. - context-independence: replace the empty-options babel-loader with a local pass-through identity-loader, keeping a loader-processed module in the graph. Remove the now-obsolete test.filter.js gates and babel.config.js, and refresh the snapshots (only deterministic chunk ids and react module grouping change).
…e unavailable Build-dependency capture reconstructs a CJS file's dependencies from its require.cache children. Bun doesn't populate module.children, so the walk silently misses transitive requires made from inside node_modules — build dependencies aren't tracked and the persistent cache can go stale. On Bun only, when module.children is empty, parse the source with acorn and enqueue its static require() specifiers (best effort, unresolved ones tolerated). The fallback is gated behind a runtime check so Node and Deno, which populate module.children, pay nothing for it. This un-skips the BuildDependencies suite on Bun.
The idle-timer cases used jest.useFakeTimers/advanceTimersByTime, which need @sinonjs/fake-timers — uninstallable on Bun, so they were skipped there. Replace them with a runtime-agnostic harness that patches global setTimeout/clearTimeout, so the cases run on Node, Deno and Bun alike.
…runs puppeteer-core is ESM-only (v25+); the top-level require() throws "Must use import to load ES Module" under Jest's vm, so puppeteer was always undefined and the whole WebpackDevServer suite silently self-skipped on every runtime (Node included), despite its existing jest-on-Bun workarounds. Load puppeteer-core with dynamic import() in beforeAll (as ProfilingPlugin's Chrome test already does) and gate itChrome on Node support + webpack-dev-server instead of the failed require. The three cases now actually run wherever a launchable Chrome is present — Node and Bun alike (verified on Node); they still self-skip cleanly when no browser can launch.
The 143 per-entry "should load" checks were skipped on Bun for an alleged OOM that doesn't reproduce: loading all 143 serializables costs only a few MB (~5MB heap under bun --smol) and the checks all pass under jest-on-Bun. Only the generator check genuinely fails on Bun (prettier trips Bun's module builtin), so keep just that one skipped and correct the comment.
🦋 Changeset detectedLatest commit: f7b974e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
This PR is packaged and the instant preview is available (6926396). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@6926396
yarn add -D webpack@https://pkg.pr.new/webpack@6926396
pnpm add -D webpack@https://pkg.pr.new/webpack@6926396 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21531 +/- ##
=======================================
Coverage 93.79% 93.80%
=======================================
Files 620 620
Lines 73327 73329 +2
Branches 21202 21202
=======================================
+ Hits 68776 68784 +8
+ Misses 4551 4545 -6
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:
|
- eslint: allow dynamic import() in WebpackDevServer.longtest (ecmaVersion 2020), fixing the "Unexpected token import" parse error. - prettier: reformat ProfilingPlugin.unittest with Prettier 3 (the itChrome call). - lazyCompilationBackend test: iterate the timer Set directly (no useless spread). - FileSystemInfo: mark the Bun-only require()-parsing fallback with istanbul ignore — it's exercised by BuildDependencies.longtest on the Bun CI job, which doesn't upload coverage, so the Node coverage run can't reach it.
Merging this PR will improve performance by ×2.4
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ⚡ | Memory | benchmark "devtool-eval", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
3.1 MB | 1.3 MB | ×2.4 |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/liar-skipped-tests-deno-bun-w127yo (f7b974e) with main (bcb1abd)
Summary
Several test suites were silently skipped on Bun/Deno — and a few were effectively dead on Node too. This PR investigates each skip, fixes the ones that were webpack-side or over-broad, and keeps only the genuine engine limitations skipped (with accurate comments).
Includes one runtime-correctness fix: webpack's persistent-cache build-dependency capture relied on
require.cachemodule.children, which Bun doesn't populate, so transitive CommonJS build dependencies went untracked and the cache could go stale. Whenmodule.childrenis empty on Bun, webpack now parses the source (acorn) for staticrequire()specifiers. Node/Deno keep using the populated children (gated, zero cost).The rest is test enablement, verified on Node, Bun 1.3.11 and Deno 2.9.4:
require("puppeteer-core")throwsMust use import to load ES Moduleunder Jest (puppeteer-core@25 is ESM-only). Load it via dynamicimport()inbeforeAll(as the ProfilingPlugin Chrome test already does) — now runs wherever a launchable Chrome exists.@babel/core@8dependency (JSX →React.createElement; a local identity loader) so they run on all runtimes.@sinonjs/fake-timers, uninstallable on Bun) with a runtime-agnostic timer harness.v8.serialize, so it runs on Bun/Deno.requirechecks were skipped for an OOM that doesn't reproduce (loading all 143 costs ~5 MB underbun --smol); only the prettier-based generator check stays skipped on Bun.What kind of change does this PR introduce?
fix (a persistent-cache correctness fix, plus substantial test-suite enablement across Node/Bun/Deno).
Did you add tests for your changes?
Yes — this PR is largely test changes. The build-dependency fix is covered by
BuildDependencies.longtest(now un-skipped on Bun) and verified on Node by forcing the source-parse fallback path.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
AI-assisted: I used Claude Code to investigate each skipped test, reproduce failures on Node/Bun/Deno, implement the fixes, and verify them (empirical measurements and targeted runs, not guesses). I reviewed every change before committing.
Generated by Claude Code
Note
Medium Risk
The production change touches persistent-cache build-dependency resolution (best-effort static require parsing on Bun only); incorrect or incomplete dependency edges could affect cache invalidation on Bun, while Node/Deno behavior is unchanged.
Overview
Fixes persistent-cache build-dependency capture on Bun by adding a Bun-only fallback when
require.cacheentries have an emptymodule.childrenlist: webpack reads the file and uses acorn to collect staticrequire("literal")specifiers (Node/Deno keep the existing children walk with no extra cost).The rest of the PR re-enables or hardens tests that were skipped or broken on alternate runtimes:
BuildDependencies.longtestruns on Bun again (noit.skip);LazyCompilationBackend.unittestuses a custom timer harness instead of Jest fake timers.WebpackDevServer.longtestandProfilingPlugin.unittestload puppeteer-core via dynamicimport()and use visibleit.skipwhen Chrome/Node prerequisites are missing.BinaryMiddlewareV8 version test builds a minimal0xff+ version payload so it works across Node/Deno/Bun.dynamic-importandcontext-independencedrop babel-loader /@babel/core@8in favor ofReact.createElementand a local identity-loader; related snapshots and filters are updated.internalSerializablesper-entry load tests run on Bun; only the prettier generator check stays Node-only.Reviewed by Cursor Bugbot for commit f7b974e. Bugbot is set up for automated code reviews on this repo. Configure here.