feat: add universal target preset (browser + web worker + Node.js + Electron + NW.js)#21214
Conversation
…test Add a dedicated `universal` target that merges `web` and `node` features, so users can write `target: "universal"` instead of `target: ["web", "node"]`. Add a comprehensive configCase exercising most module types webpack supports (esm, commonjs, json, deferred imports, source-phase imports, externals, dynamic import, top-level await, asset modules, css + css modules, html, wasm, workers) run under node, web and the universal target. Update the test runner to expand the `universal` preset to web + node when running universal bundles once per environment.
Expand the `universal` preset to merge web + webworker + node so it also covers Web Worker environments (previously `webworker` was `false`), and have it always declare ECMAScript module support. Default `experiments.outputModule` to true for universal targets: the target only works as ESM, so `target: "universal"` now builds out of the box instead of failing chunk-format selection.
The universal preset resolved its properties by calling getTargetProperties for web/webworker/node and merging on every lookup. Replace that with the equivalent static literal (byte-identical result).
…equire Extend the universal preset to span Electron (all contexts) and NW.js in addition to browser, web worker and Node.js, so it externalizes the matching built-ins. Since universal output is always ESM, set `require` (synchronous CommonJS require) to false; node built-ins and `global` stay ambiguous (null) because they remain available under Node.js ESM.
Add the remaining asset cases to the comprehensive universal test: asset/bytes, auto asset, and the `type: text` / `type: bytes` import attributes, plus css/global and import.meta.webpackContext. Add a per-config environment assertion; the universal config executes the same bundle in both a node-like and a web-like environment.
🦋 Changeset detectedLatest commit: 8878879 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 (4b00f6e). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@4b00f6e
yarn add -D webpack@https://pkg.pr.new/webpack@4b00f6e
pnpm add -D webpack@https://pkg.pr.new/webpack@4b00f6e |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #21214 +/- ##
==========================================
+ Coverage 92.74% 92.75% +0.01%
==========================================
Files 591 591
Lines 64304 64334 +30
Branches 17863 17877 +14
==========================================
+ Hits 59641 59676 +35
+ Misses 4663 4658 -5
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 degrade performance by 50.86%
Warning Please fix the performance issues or acknowledge them on CodSpeed. Performance Changes
Tip Investigate this regression by commenting Comparing |
Summary
Adds a dedicated
universaltarget preset so users can writetarget: "universal"instead oftarget: ["web", "node"]. The preset mergesweb+web worker+node+electron+nwjsplatform features, always outputs ECMAScript modules (it defaultsexperiments.outputModuletotrue, since universal only works as ESM), and never exposes synchronous CommonJSrequire. It resolves to a static property literal (no per-lookup merge). Also adds a largeconfigCases/target/universal-all-module-typescase that exercises (almost) every module/asset type webpack supports — run undernode,web, anduniversal, where the universal bundle executes once in a node-like and once in a web-like environment.What kind of change does this PR introduce?
feat
Did you add tests for your changes?
Yes —
test/configCases/target/universal-all-module-types/*(ESM, CommonJS, JSON, deferred/source-phase imports, dynamic import + context, top-level await, externals, all CSS variants, HTML, async WASM, workers, and every asset module type incl.type: text/type: bytes), and atarget: "universal"snapshot intest/Defaults.unittest.js.Does this PR introduce a breaking change?
No.
target: "universal"is new; existing targets are unchanged. Defaultingexperiments.outputModulefor universal only affects configs that previously errored at chunk-format selection.If relevant, what needs to be documented once your changes are merged or what have you already documented?
The new
target: "universal"value (browser + web worker + Node.js + Electron + NW.js, ESM-only). Known limitation to note in docs: live CSS hot-updates do not apply on the Node side of a universal build (nodocument→ no-op); JS module HMR works in both environments.Use of AI
AI (Claude Code) was used to research the existing universal-target handling, implement the preset and defaults wiring, author the comprehensive test case, and iterate until the suites passed. All changes were reviewed and verified locally.
Generated by Claude Code