Add HMR test suite for universal (node + web) targets#21193
Conversation
Add HotTestCasesUniversal that builds hot cases as a universal target (["web", "node"], ESM output) and runs each bundle in both a web and a node environment, mirroring the universal handling in the config-cases runner. Cover the module types (ESM, CommonJS interop, JSON, dynamic import, import attributes, defer import) plus a multi-target case that also exercises the webworker environment.
Guard the CSS style-injection runtime and the `css-style-sheet` export so universal/neutral targets no longer reference `document`/`CSSStyleSheet` in node; `css-style-sheet` falls back to the raw CSS text there. Add universal hot cases for wasm and for CSS export types (locals, text, style, css-style-sheet), and teach the test runner's `fetch` to serve a real Response (arrayBuffer/text + wasm mime) so async wasm loads in the web environment.
Replace the universal-config detection with a check that the target lists both a node-like and a web-like environment, as a stand-in until a real universal target lands. Drop the `universal` suite flag in favour of it. Revert the `css-style-sheet` neutral-platform fallback and its hot case; that export type stays web-only for now. The `style` injection guard and its node+web hot case remain.
Restore the general isUniversalTarget check (covers web+node, electron, webworker and other neutral-platform combos) instead of a node+web-only probe, in preparation for a dedicated universal target. The hot suite derives its behavior from it rather than a config flag.
🦋 Changeset detectedLatest commit: 7e91224 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 (b6d570d). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@b6d570d
yarn add -D webpack@https://pkg.pr.new/webpack@b6d570d
pnpm add -D webpack@https://pkg.pr.new/webpack@b6d570d |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21193 +/- ##
=======================================
Coverage 92.70% 92.70%
=======================================
Files 588 588
Lines 64091 64122 +31
Branches 17785 17799 +14
=======================================
+ Hits 59416 59447 +31
Misses 4675 4675
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 49.16%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | benchmark "many-chunks-esm", scenario '{"name":"mode-production","mode":"production"}' |
7.1 MB | 10.1 MB | -29.6% |
| ⚡ | Memory | benchmark "asset-modules-inline", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
1,293.6 KB | 324.6 KB | ×4 |
| ⚡ | Memory | benchmark "side-effects-reexport", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
1,208.6 KB | 760.9 KB | +58.85% |
| ⚡ | Memory | benchmark "asset-modules-bytes", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
326.8 KB | 247.8 KB | +31.85% |
| ⚡ | Memory | benchmark "devtool-source-map", scenario '{"name":"mode-production","mode":"production"}' |
7.7 MB | 6.2 MB | +25.66% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing test/universal-target-hmr (7e91224) with main (8596a28)
The async-wasm bundle is an async module (top-level await) and its web path needs `Response`, so the case fails to parse/run on Node 10/12. Filter it to WebAssembly- and Response-capable Node, matching the configCases/wasm/universal guard.
Summary
We test HMR per single target (
HotTestCasesNode,HotTestCasesWeb, …) but never assert that a universal build (one ESM bundle for both node and web) hot-updates correctly in every environment. This addsHotTestCasesUniversal, which builds each opted-in hot case as a universal target (["web", "node"], ESM output) and runs the same bundle once per environment — reusing the existingTestRunner.isUniversalTargetexpansion (web+node, electron, webworker, …).New
test/hotCases/universal/cases cover the module types: ESM, CommonJS interop, JSON, dynamic import, import attributes (with { type }),import defer, async WebAssembly, CSS (locals /text/styleexport types), and a["web", "node", "webworker"]multi-target case.Supporting changes: a small runtime guard so CSS
styleinjection no-ops when there is nodocument(universal/node), and the test runner'sfetchnow returns a realResponse(witharrayBuffer/wasm mime type) so async wasm loads in the web environment.What kind of change does this PR introduce?
test (plus a small CSS-runtime guard).
Did you add tests for your changes?
Yes — this PR is the tests:
test/HotTestCasesUniversal.test.js, the sharedtest/HotTestCases.template.js, and thetest/hotCases/universal/*cases. The CSSstyleguard is exercised bytest/hotCases/universal/css-export-type-style.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 — no public API change. The universal target itself remains emulated (see follow-ups) and is not yet a documented option.
Use of AI
Yes. Authored with Claude Code: it explored the hot-test/runner harness, wrote the suite and cases, made the CSS/harness changes, and ran the suites locally; all changes were reviewed before committing.
Follow-ups needed for full universal-target support
This PR only adds coverage and the minimal runtime guards needed to run it. To actually ship a universal target, these still need work:
target: "universal"— today it is emulated with["web", "node"]+output.module; a dedicated target should set the neutral platform (web=null,node=null) directly so users don't hand-assemble it.css-style-sheetexport type — depends onCSSStyleSheet, which is absent in node, so it stays web-only for now; needs an SSR-friendly universal behavior before it can run universally (this PR intentionally has no node fallback for it).styleinjection in node — currently a no-op (nodocument); for SSR it should collect/expose styles server-side instead of silently dropping them.document-guarded and no-ops; universal SSR needs node-side CSS retrieval (e.g. reading the emitted file) so server output includes styles.new Worker(new URL(...))across Web Workers vs nodeworker_threadsneeds runtime + test coverage.fetchvsfs).typeof document/self !== "undefined"; a single shared universal platform-detection helper would be more robust.import source) and source-phase wasm,asset/resourcepublic-path resolution, and externals (node builtins vs browser) under a universal target.Generated by Claude Code