Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vite not tree-shaking dynamic imports #14145

Open
7 tasks done
benlind opened this issue Aug 17, 2023 · 9 comments · May be fixed by #14221
Open
7 tasks done

Vite not tree-shaking dynamic imports #14145

benlind opened this issue Aug 17, 2023 · 9 comments · May be fixed by #14221
Labels
has workaround p3-significant High priority enhancement (priority)

Comments

@benlind
Copy link

benlind commented Aug 17, 2023

Describe the bug

Vite 4.4.9 is not tree-shaking the contents of dynamically-imported modules:

// utils.js
export function export1() {
  console.log('export1')
}
export function export2() {
  console.log('export2')
}

// main.js
async function main() {
  const { export1 } = await import('./utils.js')
  export1()
}
main()

In the above example, even though only export1 is imported, both export1 and export2 will be bundled by Vite.

If you use a static import, export2 is correctly tree-shaken from the final bundle:

import { export1 } from './utils.ts'
export1()

Rollup has supported dynamic import tree-shaking since 3.21.0 (description of feature, PR), and Vite 4.4.9 is using Rollup 3.28.0, so Vite should also support it.

Vite #11080 was closed saying "rollup now supports this," but the repro link was not a Vite repro, but a vanilla Rollup repro. I attached a vanilla Vite repro, and here is a Vite Vue TS repro.

Finally, here is a repro of Rollup correctly tree-shaking the dynamic import.

Reproduction

https://stackblitz.com/edit/vitejs-vite-z6x1lz?file=main.js

Steps to reproduce

  1. Open the repro stackblitz
  2. npm run dev
  3. Look at the dist/ output for "export4". It will appear even though it shouldn't.

System Info

Stackblitz

Used Package Manager

npm

Logs

No response

Validations

@benlind benlind changed the title Vite not tree-shaking dynamic import Vite not tree-shaking dynamic imports Aug 17, 2023
@sapphi-red
Copy link
Member

Ah, I guess this is happening because Vite replaces

const { export3 } = await import('./not-tree-shaken.js');
// into
const { export3 } = await __vitePreload(() => import('./not-tree-shaken.js'), []);

Then, rollup fails to analyze this.

@sapphi-red sapphi-red added has workaround p3-significant High priority enhancement (priority) labels Aug 18, 2023
@bdezso

This comment was marked as duplicate.

@benlind
Copy link
Author

benlind commented Aug 18, 2023

@sapphi-red , I see you added the "has workaround" label. Are you aware of a workaround?

@sapphi-red
Copy link
Member

This workaround (#11080 (comment)) should still work.

@benlind
Copy link
Author

benlind commented Aug 22, 2023

Thanks for the link.

Unfortunately that workaround is too unwieldy for my use case. I'm using a "main": "index.ts" file in my package.json in a monorepo, and I want to support dynamic importing from that main file (I'm also using Webpack 4, which doesn't support the "exports" field, which would have let me use multiple exports). I would have to create facade files in every other package that uses this package for every one of the many exports.

@sapphi-red
Copy link
Member

(I'm also using Webpack 4, which doesn't support the "exports" field, which would have let me use multiple exports)

You don't need to use exports field for multiple exports. If you don't declare exports field, all files are exposed. For example, if you have a package named foo and have bar.ts in the root directory of the package, you can import that file with foo/bar.ts.

@benlind
Copy link
Author

benlind commented Aug 23, 2023

Certainly true, though in our monorepo we enforce importing from the canonical main files for structure/API hygiene.

@ccreusat
Copy link

ccreusat commented Jan 12, 2024

Hi,

I'm coming from this issue rollup/rollup#4951 and I cannot import dynamic component from a react library:

const OnboardingModal = lazy(async () => {
  const module = await import("@edifice-ui/react");
  return { default: module.OnboardingModal };
});

This will break tree-shaking and imports whole library..

I have to import and re-export my component to use it without importing whole library.

// Example
import { OnboardingModal } from "@edifice-ui/react";

export default OnboardingModal;

Then I can use lazy / await import

const OnboardingModal = lazy(async () => await import("./Re-export"));

Any idea if it's possible since this PR was merged ?

I don't know if there is any point in re-exporting to use Suspense/Lazy instead of a static import.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
has workaround p3-significant High priority enhancement (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants