Repository navigation
fix: prevent cycles for indirectly awaited dynamic imports - #6516
lukastaegert merged 4 commits into
Conversation
|
@ryanchou1994 is attempting to deploy a commit to the rollup-js Team on Vercel. A member of the Team first needs to authorize it. |
|
Hi @lukastaegert, following up on this. I replied to the Copilot comment above with the fixture results (the indirectly awaited case is covered by the added tests, and the remaining dead-lock variant is outside this PR's scope). Happy to adjust if you see it differently. Also, if you get a chance, could you approve the CI run so it can run on this branch? |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #6516 +/- ##
=======================================
Coverage 98.15% 98.15%
=======================================
Files 379 379
Lines 13805 13826 +21
Branches 2925 2927 +2
=======================================
+ Hits 13550 13571 +21
Misses 212 212
Partials 43 43 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Performance report
|
Thank you for your contribution! ❤️You can try out this pull request locally by installing Rollup via npm install ryanchou1994/rollup#fix/preserve-entry-side-effect-splitNotice: Ensure you have installed the latest nightly Rust toolchain. If you haven't installed it yet, please see https://www.rust-lang.org/tools/install to learn how to download Rustup and install Rust. or load it into the REPL: https://rollup-3ighjiwpu-rollup-js.vercel.app/repl/?pr=6516 Warning The REPL link above is outdated: the available artefacts represent an earlier commit and do not include the latest changes of this pull request. |
lukastaegert
left a comment
There was a problem hiding this comment.
Hi, thank you for looking into this. While your approach is rather radical, it could be argued that the general idea is acceptable.
However, your approach is not as conservative as you think, here is actually a regression when compared to master, i.e. your logic can actually introduce additional cycles, not only prevent them:
Compare this with the master version that does not fold shared into main.
Marking every dynamic import reached from an entry with a top-level await as awaited was not conservative: the awaited already-loaded atoms were intersected over all awaiting importers, so an additional awaiting importer that had not loaded a shared chunk itself could drop that chunk from the protected set. The chunk was then merged into the entry and the dynamic entry imported the entry back, creating a new cycle. Awaited already-loaded atoms are now the union over all awaiting importers, and entries that await a dynamic entry indirectly are registered as awaiting importers of that entry.
|
Thanks for the REPL, you are right. Marking every dynamic import reached from an entry with a top-level await as awaited was only half of it: the awaited already-loaded atoms were intersected over all awaiting importers, so once Pushed 5bd6869 on top of your merge:
The full suite passes locally and no existing expected output changed, so the union does not alter chunking for the current fixtures. The known gap where the generated with AI |
|
This PR has been released as part of rollup@4.64.5. You can test it via |

This PR contains:
Are tests included?
Breaking Changes?
List any relevant issue numbers:
Description
With
preserveEntrySignatures: false, awaited dynamic imports keep their dependent-entry coloring so shared modules are not merged into an entry that is still evaluating. The existing analysis only recognized a directawait import(). When top-level await calls through a static dependency that performs the dynamic import, the shared module could instead be merged into the entry, making the dynamic chunk import back from that evaluating entry and creating a cycle.Track dynamic entries reached by each static dependency graph and, when that graph contains top-level await, preserve their awaited coloring. This is intentionally conservative: an unawaited dynamic import reachable from the same graph can retain an extra shared chunk, but it avoids an incorrect cycle when the await relationship is indirect and cannot be recovered from the direct importer metadata.
The new chunking fixture covers both ES and SystemJS output. The focused fixture, the full chunking suite, the full core suite, targeted ESLint, and formatting checks pass on macOS and Linux.
generated with AI