feat: keep export mangling for modules whose namespace object escapes#21234
Merged
Conversation
🦋 Changeset detectedLatest commit: 29f6ab1 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 |
Contributor
|
This PR is packaged and the instant preview is available (eefaf44). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@eefaf44
yarn add -D webpack@https://pkg.pr.new/webpack@eefaf44
pnpm add -D webpack@https://pkg.pr.new/webpack@eefaf44 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #21234 +/- ##
==========================================
- Coverage 92.82% 92.81% -0.01%
==========================================
Files 592 592
Lines 64829 64964 +135
Branches 18067 18135 +68
==========================================
+ Hits 60175 60299 +124
- Misses 4654 4665 +11
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:
|
2d6c314 to
8488e61
Compare
8488e61 to
933c64a
Compare
Member
|
LGTM, it's nice improvement for the whole namespace accessing. |
82fec1b to
d962c7c
Compare
When a module's namespace object is used as a whole value (for example re-exported and returned, spread, or passed around) export mangling was disabled for the whole module, bloating every reference in all other consumers. Such modules now keep their exports mangleable: the escaping reference is rendered as a decoupled namespace object that exposes the original export names via getters onto the mangled bindings, so access by the original name keeps working. Driven by optimization.mangleExports, for both non-concatenated and concatenated builds. Left conservative (unchanged) for CommonJS interop, dynamic imports and deferred imports. To preserve ES module namespace semantics on the escaping module, its exports stay non-inlinable and member access keeps a qualified property access: a missing export reads as `ns.x` (not a bare `undefined`) and `delete ns.x` hits a real non-configurable binding, so it stays valid and throws where the spec requires. Closes #19153.
Clarify the PR-body guidance to use the auto-closing `Closes #…`/`Fixes #…` form when the PR actually fixes the bug or implements the requested feature, reserving `Refs #…` for issues a PR only relates to.
d962c7c to
29f6ab1
Compare
Contributor
Types CoverageCoverage after merging claude/webpack-pr-19219-4mh8ue into main will be
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a module's namespace object is used as a whole value (for example re-exported and returned, spread, or passed around), export mangling was disabled for the entire module, so every reference in all other consumers kept full export names — bloating the output.
This PR keeps such modules mangleable: the escaping reference is rendered as a decoupled namespace object whose getters expose the original export names onto the mangled bindings, so access by the original name (including dynamic/
Object.keys) keeps working. It is driven byoptimization.mangleExportsand works for both non-concatenated and concatenated builds (inner, external/standalone, and code-split shared modules). CommonJS interop, dynamic imports and deferred imports are left conservative (unchanged). Closes #19153.On a barrel-with-escape build (1 escaping module, 300 exports, 150 static consumers, minified) the output drops from 38.4 KB → 17.2 KB raw (−55%) / 5.3 KB → 4.3 KB gzip (−19%), with no build-time or peak-memory regression.
What kind of change does this PR introduce?
feat
Did you add tests for your changes?
Yes — new
test/configCases/mangle/mangle-escaping-namespaceand…-concatcases covering ESM named/default exports,export * asre-exports, CommonJS interop, destructuring of an escaping module, dynamically imported namespaces, inlined-const exports, namespace enumeration, anddelete ns.memberon an escaping namespace; plus updatedmangle-with-destructuring-assignmentandcode-generation/re-export-namespace-concatto the new (runtime-identical) output. Verified against thetest262module-namespace[[Delete]]cases.Does this PR introduce a breaking change?
No. Runtime semantics are unchanged (verified across all the contexts above); only the generated output is smaller because more exports get mangled.
If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a — no new option;
optimization.mangleExportsnow also applies to modules whose namespace object escapes.Use of AI
AI (Claude Code) was used to implement the change, write the tests, run the test suite, measure output size / build time / memory, and investigate edge cases across rendering contexts. All output was reviewed and validated against the webpack test suite.
Generated by Claude Code