Skip to content

fix: skip dropping side-effects on namespaceReexportsByName cache hit (#6274)#6286

Merged
lukastaegert merged 3 commits intorollup:masterfrom
littlegrayss:fix-issue-6274
Mar 29, 2026
Merged

fix: skip dropping side-effects on namespaceReexportsByName cache hit (#6274)#6286
lukastaegert merged 3 commits intorollup:masterfrom
littlegrayss:fix-issue-6274

Conversation

@littlegrayss
Copy link
Copy Markdown
Contributor

@littlegrayss littlegrayss commented Mar 1, 2026

This PR contains:

  • bugfix
  • feature
  • refactor
  • documentation
  • other

Are tests included?

  • yes (bugfixes and features will not be merged without tests)
  • no

Breaking Changes?

  • yes (breaking changes will not be merged unless absolutely necessary)
  • no

List any relevant issue numbers:

Description

When multiple entry points import the same export through a namespace re-export chain (export * from ...), the namespaceReexportsByName cache 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 namespaceSideEffectsByName cache is introduced alongside namespaceReexportsByName. 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 (sideEffectCollector and cyclicReexporterCollector) are threaded through getVariableForExportName and getVariableFromNamespaceReexports to 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).

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 1, 2026

@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
Copy link
Copy Markdown

codecov bot commented Mar 3, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.78%. Comparing base (6ecd69f) to head (5154ad7).
⚠️ Report is 9 commits behind head on master.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

littlegrayss and others added 3 commits March 23, 2026 20:44
…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.
@TrickyPi
Copy link
Copy Markdown
Member

Thanks for the update. I simplified the implementation and added the missing tests on your branch.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
rollup Ready Ready Preview, Comment Mar 28, 2026 6:45am

Request Review

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 / getVariableFromNamespaceReexports to cache and replay side-effect and reexport-chain metadata on export * 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.

@lukastaegert lukastaegert added this pull request to the merge queue Mar 29, 2026
Merged via the queue into rollup:master with commit 51f8f60 Mar 29, 2026
51 checks passed
@github-actions
Copy link
Copy Markdown

This PR has been released as part of rollup@4.60.1. You can test it via npm install rollup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

namespaceReexportsByName cache skips side-effect recording for subsequent importers via export *

5 participants