feat: defer building unused reexport targets of barrel modules#21165
Conversation
🦋 Changeset detectedLatest commit: 755fe7d 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 (671eb14). Install it locally:
npm i -D webpack@https://pkg.pr.new/webpack@671eb14
yarn add -D webpack@https://pkg.pr.new/webpack@671eb14
pnpm add -D webpack@https://pkg.pr.new/webpack@671eb14 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #21165 +/- ##
==========================================
+ Coverage 92.70% 92.72% +0.01%
==========================================
Files 588 589 +1
Lines 64091 64335 +244
Branches 17785 17843 +58
==========================================
+ Hits 59416 59652 +236
- Misses 4675 4683 +8
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:
|
80ebe1b to
c84dd73
Compare
experiments.lazyBarrel to skip building unused module4125aff to
4c1ef43
Compare
| new LibManifestPlugin({ ...this.options, entryOnly }).apply(compiler); | ||
| if (!entryOnly) { | ||
| new FlagAllModulesAsUsedPlugin(PLUGIN_NAME).apply(compiler); | ||
| compiler.hooks.compilation.tap( |
There was a problem hiding this comment.
Set sideEffectFree in the earlier factorize stage to ensure it is available when processing the barrel module.
| "a.js", | ||
| "index.js", | ||
| ]); | ||
| expect(globValueModuleLog).toEqual(["index.js"]); |
There was a problem hiding this comment.
In barrel module, we will skip building the target module which isn't side-effect-free too. The behavior is aligned with rspack.
For example
// index.js
import { c } from "./barrel.js"
// barrel.js
import { b } from "./b" // We skip building `./b.js`, even if it has side effects.
export * from "./a"
export { c } from "./c"| [inactive] harmony export imported specifier ./c ./node_modules/pmodule/b.js 5:0-24 | ||
| harmony import specifier pmodule ./index.js 3:17-18 (skipped side-effect-free modules) | ||
| [inactive] harmony export imported specifier ./b ./node_modules/pmodule/index.js 2:0-30 (skipped side-effect-free modules) | ||
| ./node_modules/pmodule/a.js X bytes [orphan] [built] |
There was a problem hiding this comment.
./node_modules/pmodule/a.js will be skipped.
| modules by path ./components/src/ X bytes | ||
| orphan modules X bytes [orphan] | ||
| modules by path ./components/src/CompAB/*.js X bytes 2 modules | ||
| modules by path ./components/src/CompC/*.js X bytes 2 modules |
There was a problem hiding this comment.
./components/src/CompC/*.js will be skipped.
Types CoverageCoverage after merging feat/lazy-barrel into main will be
Coverage Report
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Summary
What kind of change does this PR introduce?
This is a port of rspack's lazy barrel optimization (RFC discussion, docs).
When importing from a
side-effect-freebarrel file, we defersfactorizing/resolving/buildingthe re-export target modules until an importer actually requests those export names, so unused re-export targets are never built, it can significantly speeding up builds that import a few names from large barrels (e.g. component libraries).The local benchmark on a M4 MacBook Pro:
Did you add tests for your changes?
Yes
Does this PR introduce a breaking change?
No
If relevant, what needs to be documented once your changes are merged or what
Document
experiments.lazyBarrelon the Experiments page: requiressideEffectodule.rules[].sideEffects), ESM only, and skipped modules never resolve/build so their resolve/loader errors and "export not found" warnings may not surface.Use of AI
Partial