Skip to content

Conversation

@privatenumber
Copy link
Contributor

@privatenumber privatenumber commented Mar 26, 2025

Description

fixes #19695

This PR fixes:

  • vitePreload injection so it doesn't get in the way of Rollup parsing named dynamic imports
  • Doesn't apply vitePreload at all if there are no dependencies to load
  • Deduplicates the chunk ID -> path mapping across chunks

I've broken this up into smaller PRs and I'm waiting for these to be reviewed and merged first:

Afterwards:

@privatenumber
Copy link
Contributor Author

privatenumber commented Mar 26, 2025

  • There's too many changes in here so I'm going to split them up into smaller PRs

await import('./custom2.js')
console.log(await import('./custom0.js'))
console.log(await import('./custom1.js'))
console.log(await import('./custom2.js'))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These imports actually have no side-effects so Rollup should have been tree-shaking them. However, the way the preload method was previously injected prevented them from getting tree-shaken.

Now that it's being applied correctly, Rollup accurately detects that their export values weren't being used, which is why I had to add console.logs here.

@privatenumber
Copy link
Contributor Author

@bluwy #16184 (review)

Thanks! This looks great to me. Something I'd also like to followup later is to remove the mapDeps altogether if no preloading is needed for the file. Currently it's added unconditionally. And the changes could get a bit big.

This PR accomplishes this.

Comment on lines +277 to +279
// To prevent dead code elimination. Will properly remove in generateBundle
// It's referenced twice so it doesn't get inlined by the minifier
${preloadSaver}(${preloadMethod},${preloadMethod});
Copy link
Member

Choose a reason for hiding this comment

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

While this can make the preloadMethod import to be kept, since this function call is treated as a sideeffect, rollup will treat this module as sideeffectful and would make the chunking less ideal.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. It's been a while, so correct me if I'm wrong, but doesn't this behavior exist with the current implementation as well?

To fix it, maybe we can create and inject the custom chunk import after all the chunks are rendered? Either way, I think this is still a big improvement compared to the build breakage that this PR resolves.

Copy link
Member

Choose a reason for hiding this comment

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

doesn't this behavior exist with the current implementation as well?

The current implementation injects the preload method right next to the dynamic import and not at the root of the module. So it doesn't mark the module as side effectful, it only marks the function that contains the dynamic import.

To fix it, maybe we can create and inject the custom chunk import after all the chunks are rendered?

Yeah, this would solve this problem. But I didn't find a way to put the preload helper in a non-separate chunk. this.emitFile({ type: 'chunk' }) should work if a separate chunk is acceptable, though it's not ideal.

I think this is still a big improvement compared to the build breakage that this PR resolves.

I made a PR that at least fixes the breakage (#20117). But I’m open to switching to a different approach, as long as the trade-offs are worthwhile.

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.

Dynamic import().then(m => m.foo) works in dev but fails in prod

2 participants