-
-
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
feat(css): allow scoping css to importers exports #16058
base: main
Are you sure you want to change the base?
Conversation
Run & review this pull request in StackBlitz Codeflow. |
Another way I can think of is to add a default export as a placeholder. The corresponding CSS will be dropped if the placeholder is dropped, and vice versa. const plugin = {
name: 'css-post-post',
transform(css, id) {
if (!(id.endsWith('.css') && id.includes('&scoped'))) return
css += '\nexport default ""'
return { code: css, moduleSideEffects: null /* not sure if this can override the value returned by vite:css-post plugin */ }
}
} // compiled main file
import placeholder from './foo.vue?vue&scoped&lang.css'
export default /* #__PURE__*/ (() => {
const component = {}
component.styles = [placeholder] // this is required and will affect the bundle size slightly
return component
}) |
Yeah that was also an option while figuring this out. Like some sort of marker that can be injected and we remove it post-render. But the caveats I think are:
But it certainly seems like the nicer API for end-users though, but ideally we only introduce a single API. |
Did another test today, and I found that it didn't have the best code-splitting if multiple entrypoints import from the barrel file. The multiple entrypoints will import a shared CSS asset that contains all the scoped CSS from the barrel file, because Rollup will initially think that the scoped CSS are all side-effect-full, so it groups them together. I guess the only correct fix is an API like Sapphi proposed. I don't think it's a dealbreaker though since extra-included scoped CSS are harmless, but it could work better with a different strategy with its own set of trade-offs too. |
Description
closes #4389
closes #15497 (doesn't exactly fix it, but unblocks downstream to fix this)
Frameworks like Vue, Svelte, and Astro has the concept of scoped CSS. Internally, they are transformed as imports to a virtual CSS module. However, the general CSS bundling flow will assume the CSS to be global, so even if the framework component is used but treeshaken, the CSS will still be kept because Vite assumes its global.
To resolve this, Vite plugins can mark certain CSS to be scoped to certain modules' exports. For example,
/src/Foo.vue?vue&type=style&lang.css
is scoped to/src/App.vue
's default export.The API this PR exposes is via
meta.vite.cssScopeTo['/src/Foo.vue'] = ['default']
set on the/src/Foo.vue?vue&type=style&lang.css
modules in Vite plugins. Now, ifFoo.vue
is not used, the styles are also treeshaken.Additional context
This only works in build, in dev it will still loaded as ESM will load it as usual (we dont treeshake in dev). However, this shouldn't be an issue in dev because the CSS should be scoped and not affect anything globally.
I can't figure out a general API that works outside of Vite plugins without magic comments. Import attributes or queries don't seem feasible because they annotate the "import statement" rather than the "rollup module" itself.
I've also tested this manually in a Svelte app. From some rough implementations, it's easiest to set the
meta
on theresolveId
hook when resolving the virtual CSS module. (implementation detail)What is the purpose of this pull request?
Before submitting the PR, please make sure you do the following
fixes #123
).