Skip to content

Conversation

@TrickyPi
Copy link
Member

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:
relevant: #6073

Description

Technically, an await expression should always have side effects, since it delays the execution of the following code. For example:

async function a() {
  await 1;
  console.log('a');
}
async function b() {
  console.log('b');
}
a();
b();

Here, 'b' is logged before 'a'.
But if the argument to await is an import() expression, I think the await expression could be safely removed. In that case, the execution timing of the following code is not deterministic anyway, since it is affected by file I/O or network requests.

@vercel
Copy link

vercel bot commented Sep 21, 2025

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

Project Deployment Preview Comments Updated (UTC)
rollup Ready Ready Preview Comment Sep 27, 2025 5:16am

@github-actions
Copy link

github-actions bot commented Sep 21, 2025

Thank you for your contribution! ❤️

You can try out this pull request locally by installing Rollup via

npm install rollup/rollup#feat/enhance-tree-shaking-for-dynamic-imports

Notice: 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-c0bw14x3x-rollup-js.vercel.app/repl/?pr=6120

@github-actions
Copy link

github-actions bot commented Sep 21, 2025

Performance report

  • BUILD: 6981ms, 829 MB
    • initialize: 0ms, 25.1 MB
    • generate module graph: 2597ms, 635 MB
      • generate ast: 1384ms, 624 MB
    • sort and bind modules: 391ms, 692 MB
    • mark included statements: 3964ms, 829 MB
      • treeshaking pass 1: 2337ms, 825 MB
      • treeshaking pass 2: 459ms, 835 MB
      • treeshaking pass 3: 390ms, 830 MB
      • treeshaking pass 4: 378ms, 827 MB
      • treeshaking pass 5: 377ms, 829 MB
  • GENERATE: 801ms (-132ms, -14.1%), 920 MB
    • initialize render: 0ms, 899 MB (-5%)
    • generate chunks: 308ms (+55ms, +21.6%), 832 MB (-10%)
      • optimize chunks: 0ms, 821 MB (-11%)
    • render chunks: 620ms (-29ms, -4.5%), 893 MB
    • transform chunks: 19ms, 920 MB
    • generate bundle: 0ms, 920 MB

@codecov
Copy link

codecov bot commented Sep 21, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.74%. Comparing base (cfe817e) to head (ddbdfef).

⚠️ Current head ddbdfef differs from pull request most recent head 70baa48

Please upload reports for the commit 70baa48 to get more accurate results.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #6120   +/-   ##
=======================================
  Coverage   98.73%   98.74%           
=======================================
  Files         271      271           
  Lines       10630    10652   +22     
  Branches     2846     2853    +7     
=======================================
+ Hits        10496    10518   +22     
  Misses         89       89           
  Partials       45       45           

☔ 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.

@lukastaegert
Copy link
Member

lukastaegert commented Sep 21, 2025

In that case, the execution timing of the following code is not deterministic anyway

You are mostly right, but it will never be synchronous, and some logic may rely on the fact that it is async. As this is hard to detect, I would suggest instead to replace it with something compact like an await 0. Which in general might be a good simplification for await without other side effects.

@TrickyPi
Copy link
Member Author

Oh, I misunderstood before. I get it now—if an async function doesn’t have an await, its execution behaves like synchronous code. Thanks for reminding me!

@TrickyPi
Copy link
Member Author

TrickyPi commented Sep 27, 2025

After thinking it through, it seems difficult to replace an awaiting import expression with 0. First, the AwaitExpression’s hasEffects function has to return true, otherwise, the render function won't run, and the replacement logic inside it won't be executed. But once we do that, the inclusion of await expressions will always be triggered, and we can’t stop this inclusion from propagating to its argument.

I originally thought shouldBeIncluded could stop the propagation, but it turns out it misses some cases. The CI failure revealed the reason: some of the propagation is triggered by the inclusion of other variables.

Maybe we have to narrow the scope of this PR and only take import expressions into account.

@lukastaegert
Copy link
Member

and we can’t stop this inclusion from propagating to its argument.

That is not true. For instance, a BlockStatement also does not propagate the inclusion to its children, and I would have hoped this can work similarly. It is wrong, though, to have conditional logic in includeNode as it only runs once. Not yet sure what the correct solution would be here.

@lukastaegert lukastaegert force-pushed the master branch 2 times, most recently from 5369863 to 96b5453 Compare November 7, 2025 21:32
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.

3 participants