-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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
CSS files cannot be treeshaken with side effects #4389
Comments
I'm confused, if the package.json marked CSS files as side-effectful, shouldn't Webpack include the CSS that would result in what Vite produces? Vite currently treats all CSS as side-effectful, and side-effect modules aren't treeshaken out because they aren't pure. So from my point of view, Vite is doing the right thing here. Can you shed some light on the issue here? |
But I just import the component |
Ah okay. Found the webpack documentation for it, it's weird that the project's Vite currently doesn't support
Vite treats all CSS files as side-effectful by default, that means even if we didn't used If you remove the |
Yeah, this feature is useful for UI library to auto import component's own style by default. |
@bluwy I think your first understanding about When this was changed like this, webpack did not output any css. "sideEffects": [
- "*.css",
"src/components/a/index.js",
"src/components/b/index.js"
], So in conclusion I think when there is |
@bluwy Is there a way to work around this behavior? Components often use scoped selectors to ensure there are no global side-effects, so it would be nice to tell vite to treat these css imports as side-effect free. I understand that this is a feature request but there must be something we (component library authors) can do or document today to reduce bundle size? |
@mayank99 I don't think there's a workaround today, but I agree there should be a way around this, like the |
I've needed something like this as well - I'm currently working on a UI component library that is optimized for server-side rendering, and the challenge I'm facing is that the app doesn't need the CSS for every component in the library, but only the components that it is actually using. I can think of several approaches - one would be a build configuration parameter telling it to treat files with the "module.css" extension differently than other imports. The other would be a doc-comment such as |
I have a Vuetify 3 + Vite project and was hoping to get rid of the unnecessary 20K lines of css from my final bundle. |
My team has a component library using different technologies for building components, like Lit and Quasar/Vue. This would be useful to help strip out unused Quasar styles. |
I'm currently looking into this as it'll benefit UI frameworks with scoped CSS. Especially for component libraries or barrel files, as today, all the scoped CSS will get bundled even if the related component is not bundled. However marking CSS are side-effect-free is technically not the solution. For example, if you have I'm currently trying to figure an API to say "this CSS import is related to this default/named export. if the export is treeshaken, also treeshake the CSS". I'm not sure if it's possible to do it automatically. Also, this issue affects CSS modules today. |
This is a tricky problem. The ideal way would be something like: "If nothing else from this module is imported, then tree-shake its CSS imports too". But I understand that's not how JS works, especially when using barrel files. I'm not sure that a new API would be useful for component library authors, because it wouldn't work with other bundlers (esbuild, webpack, etc). It would be nice if there was some consensus across different bundlers, to ease the burden from library authors. (To get around this problem today, I've resorted to removing all side-effect imports, and provide explicit CSS exports for applications to consume, which is obviously not ideal.) |
Yeah it seems like the respective issue on Webpack side is webpack-contrib/css-loader#506
This is a little risky I think. If you have a library that export Also, I think we should look at CSS treeshaking as an optimization standpoint. In dev where no treeshaking is happening, you'd load all the styles from a barrel file, but in prod, suddenly some may be missing which causes inconsistencies. The main usecase I'm looking into so far are for scoped CSS and CSS modules only, as in dev, the styles shouldn't bleed so extraneously-loaded styles are fine. In prod, we can then optimize and remove them. So from that, I think we need some sort of opt-in API and likely Vite plugins could automate it. And if it comes to that, it'll be tricky to make it bundler-agnostic. |
I think that issue is about a more granular tree shaking at selector level. The OP is writing about the same problem with us but the discussion is mainly focused on a more granular one.
I guess Webpack handles like this. I found this example (https://github.com/pp3nd3x/webpack-treeshaking-css-modules) and it looks like doing like that. (I found it at webpack-contrib/css-loader#769 (comment)) |
Yeah the linked issue seems to diverge to a different treeshaking topic, but that's the best I've found 😅 The repo you linked seems to be about "CSS modules", which I also want to cover. But my main concern of the approach proposed by Mayank was for general global CSS imports, which I don't think is safe to treeshake that way. |
Ah, I overlooked it and assumed it's the normal global CSS imports 🤦. Webpack does recommend adding |
I took another look at the repro and understand the issue better now. It isn't related to CSS at all. Webpack has a unique optimization where if you mark a barrel file as side-effect free, then any re-exports will redirect to the re-exported module directly. Specifically // src/barrel/index.js
export { a } from './a.js'
export { b } from './b.js' // src/index.js
import { a } from './barrel'
// webpack rewrites this to
// import { a } from './barrel/a.js'
// because the barrel file is marked side effect free
console.log(a) Vite intentionally doesn't have these optimizations in dev because they have perf penalties. If there's interest for it, I think #8237 is the right issue to follow. As even if we respect For this issue, I'll focus on CSS treeshaking only and will close this once it's resolved. To get the repro resolved, #8237 should be followed instead. |
It seems rollup treats each Also it seems the repro now works: https://stackblitz.com/edit/github-sqz9ee?file=package.json |
Oh interesting. I thought the behaviour would be the same so I didn't bother to check that. So I guess on the build side it is already fixed ( |
Describe the bug
vue-cli(webpack) VS vite
Reproduction
https://github.com/BuptStEve/vite-css-treeshake
npm start
to run vue-clinpm run vite
to run vitenpm run build
to run vue-clinpm run vite:build
to run viteSystem Info
Used Package Manager
yarn
Logs
No response
Validations
The text was updated successfully, but these errors were encountered: