perf: avoid the entry IIFE for multiple inlined entry modules#21151
Conversation
🦋 Changeset detectedLatest commit: 392d13b 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 (0afe292). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@0afe292
yarn add -D webpack@https://pkg.pr.new/webpack@0afe292
pnpm add -D webpack@https://pkg.pr.new/webpack@0afe292 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #21151 +/- ##
==========================================
- Coverage 92.34% 92.34% -0.01%
==========================================
Files 581 581
Lines 63258 63301 +43
Branches 17494 17506 +12
==========================================
+ Hits 58416 58455 +39
- Misses 4842 4846 +4
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:
|
…ed entries by renaming collisions When more than one entry module is inlined into a chunk, each was always wrapped in an IIFE to isolate it from the others. Under `optimization.avoidEntryIife`, extend the existing scope-analysis/renaming to the multi-entry case: top-level declarations that would collide with another inlined module's declaration, with any inlined or non-inlined module's free (global) reference, or with a reserved name are renamed, so the modules share the startup scope without a per-entry IIFE. The rename logic is shared with the existing single-entry path. Exports are preserved (a renamed exported binding is still exported under its original name).
269441a to
392d13b
Compare
Merging this PR will improve performance by 62.34%
|
| Mode | Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|---|
| ❌ | Memory | benchmark "react", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
151.4 KB | 344 KB | -56% |
| ⚡ | Memory | benchmark "lodash", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' |
859.3 KB | 125.9 KB | ×6.8 |
| ⚡ | Memory | benchmark "many-modules-commonjs", scenario '{"name":"mode-development","mode":"development"}' |
1,734 KB | 921.4 KB | +88.19% |
| ⚡ | Memory | benchmark "many-modules-commonjs", scenario '{"name":"mode-production","mode":"production"}' |
8.8 MB | 7.1 MB | +22.9% |
Tip
Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.
Comparing claude/search-todos-exclude-webpack-th5ld2 (392d13b) with main (4d366ac)
|
The flagged benchmark regression appears to be measurement noise rather than an effect of this change:
The net report is also +62% (the "improvements" like lodash ×6.8 share the same noise signature). Happy to dig into any specific case that reproduces deterministically. Generated by Claude Code |
Summary
When more than one entry module is inlined into a chunk, each was always wrapped in an IIFE to isolate it from the others — the
// TODO check globals and top-level declarations of other entries and chunk modulesinJavascriptModulesPlugin. Underoptimization.avoidEntryIife, this extends the existing scope-analysis/renaming (already used for the single-entry-with-chunk-modules case) to the multi-entry case: any top-level declaration that would collide with another inlined module's declaration, with any inlined or non-inlined module's free (global) reference, or with a reserved name is renamed, so the inlined entries share the chunk's startup scope without a per-entry IIFE. Exports are preserved. Also resolves the function's own secondary// TODO:.What kind of change does this PR introduce?
perf
Did you add tests for your changes?
Yes —
test/configCases/module/iife-multiple-entry-modules(collision now resolved by renaming, plus anavoidEntryIife: falsevariant that keeps the IIFE),…-no-collision(disjoint names → no IIFE), and…-library(an exported binding that collides is renamed internally yet still exported correctly, verified by executing the emitted CommonJS library).Does this PR introduce a breaking change?
No. The change only takes effect under
optimization.avoidEntryIifeand only affects inlined-startup output; there is no public API change.If relevant, what needs to be documented once your changes are merged or what have you already documented?
n/a
Use of AI
AI (Claude) was used to investigate the TODO, design the renaming extension, write the tests, and run the validation/benchmarks. All output was reviewed and verified by executing the generated bundles and running the full webpack test suites (ConfigTestCases, StatsTestCases, TestCasesNormal).
Generated by Claude Code