fix: skip dropping side-effects on namespaceReexportsByName cache hit (#6274)#6286
Conversation
|
@littlegrayss is attempting to deploy a commit to the rollup-js Team on Vercel. A member of the Team first needs to authorize it. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6286 +/- ##
=======================================
Coverage 98.78% 98.78%
=======================================
Files 274 274
Lines 10772 10788 +16
Branches 2878 2881 +3
=======================================
+ Hits 10641 10657 +16
Misses 89 89
Partials 42 42 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
…rollup#6274) When multiple entries reference the same variable via a namespace re-export, the `namespaceReexportsByName` cache was returning early. This prevented `getVariableFromNamespaceReexports` from capturing the side-effect dependencies for the subsequent importers, leading to dropped side effects (such as CSS imports). This fix explicitly re-invokes `getVariableFromNamespaceReexports` when the cache is hit and an `importerForSideEffects` is provided, utilizing its traversal to correctly link side effects to the new importer, while ignoring the return value. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
…ceReexportsByName cache hit Replace the re-traversal approach with a parallel `namespaceSideEffectsByName` cache that stores the collected side-effect modules and cyclic reexporters on first resolution. Cache hits now replay the stored metadata for each importer directly, avoiding redundant graph traversal while preserving correct side-effect tracking across multiple importers. Update the test to cover the multi-entry scenario where two entries resolve the same export through the namespace reexport cache.
c92d7df to
5154ad7
Compare
|
Thanks for the update. I simplified the implementation and added the missing tests on your branch. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
Fixes a Rollup module graph bug where namespaceReexportsByName cache hits for export * could skip registering side-effect dependencies (and related cyclic reexport handling) for subsequent importers, leading to dropped side effects in bundled output.
Changes:
- Extends
Module.getVariableForExportName/getVariableFromNamespaceReexportsto cache and replay side-effect and reexport-chain metadata onexport *cache hits. - Adds a chunking-form regression test to ensure side-effectful modules are preserved for multiple entry points across formats.
- Adds a function test covering cyclic reexport scenarios with multiple importers when namespace reexport caching is involved.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/Module.ts | Caches and replays side-effect + cyclic reexport metadata for export * namespace reexport cache hits. |
| test/function/samples/circular-namespace-reexport-cache/_config.js | Asserts warnings for cyclic reexports when multiple importers hit the namespace reexport cache. |
| test/function/samples/circular-namespace-reexport-cache/main.js | Sample entry aggregating two importers to exercise cyclic graph behavior. |
| test/function/samples/circular-namespace-reexport-cache/entry1.js | Sample importer #1 for the cyclic namespace reexport scenario. |
| test/function/samples/circular-namespace-reexport-cache/entry2.js | Sample importer #2 for the cyclic namespace reexport scenario. |
| test/function/samples/circular-namespace-reexport-cache/lib/index.js | Barrel module using export * to trigger namespace reexport caching. |
| test/function/samples/circular-namespace-reexport-cache/lib/foo.js | Reexport + side-effect import to participate in cyclic chain. |
| test/function/samples/circular-namespace-reexport-cache/lib/fooImpl.js | Implementation module that creates cycles by importing entry modules. |
| test/function/samples/circular-namespace-reexport-cache/lib/effect.js | Side-effect module used by the cyclic scenario. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_config.js | Configures treeshake side-effects to reproduce/guard against the cache-hit side-effect drop. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/entry1.js | Entry point #1 importing through export * barrel. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/entry2.js | Entry point #2 importing through export * barrel (regression target). |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/lib/index.js | Barrel module using export * to drive namespace reexport caching. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/lib/foo.js | Reexport + side-effect import module (should be retained for both entries). |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/lib/fooImpl.js | Export implementation for the chunking-form regression test. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/lib/effect.js | Side-effect module that must remain reachable from both entries. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/es/generated-effect.js | Expected ES output for shared side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/es/entry1.js | Expected ES entry1 to depend on side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/es/entry2.js | Expected ES entry2 to depend on side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/cjs/generated-effect.js | Expected CJS output for shared side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/cjs/entry1.js | Expected CJS entry1 to require side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/cjs/entry2.js | Expected CJS entry2 to require side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/amd/generated-effect.js | Expected AMD output for shared side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/amd/entry1.js | Expected AMD entry1 to depend on side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/amd/entry2.js | Expected AMD entry2 to depend on side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/system/generated-effect.js | Expected System output for shared side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/system/entry1.js | Expected System entry1 to depend on side-effect chunk. |
| test/chunking-form/samples/namespace-reexport-side-effect-cache/_expected/system/entry2.js | Expected System entry2 to depend on side-effect chunk. |
|
This PR has been released as part of rollup@4.60.1. You can test it via |
This PR contains:
Are tests included?
Breaking Changes?
List any relevant issue numbers:
Description
When multiple entry points import the same export through a namespace re-export chain (
export * from ...), thenamespaceReexportsByNamecache causes an early return on subsequent lookups. This skipped the side-effect dependency recording for the new importer, resulting in dropped side effects (e.g. CSS imports, console statements) in the bundled output.Root cause: On a cache hit, the code returned the cached variable immediately without registering side-effect dependencies for the current
importerForSideEffects.Fix: A parallel
namespaceSideEffectsByNamecache is introduced alongsidenamespaceReexportsByName. On first resolution, the collected side-effect modules and cyclic reexporters are stored. On subsequent cache hits, the stored metadata is replayed for each new importer directly — avoiding redundant graph re-traversal while preserving correct side-effect tracking.Two new optional parameters (
sideEffectCollectorandcyclicReexporterCollector) are threaded throughgetVariableForExportNameandgetVariableFromNamespaceReexportsto gather this metadata during the initial traversal.The test covers two entry points that both import the same export through a namespace re-export chain including a side-effectful module, verifying that side effects are preserved for all importers across all four output formats (es, cjs, amd, system).