vite
vite copied to clipboard
PostCSS not applied to imports via `composes`
Describe the bug
I'm trying to have styles included in a CSS module via composes
processed by PostCSS, but it's not happening. All other styles are processed by PostCSS correctly.
Take the following CSS modules and PostCSS config:
{
"plugins": {
"postcss-preset-env": {
"browsers": "defaults, ie >= 11",
"importFrom": [
"./src/variables.css"
]
},
"postcss-nested": { }
}
}
/* variables.css */
:root {
--color-red: red;
--color-blue: blue;
}
/* component.module.css */
.component {
color: var(--color-red);
.nested {
width: 100%;
}
}
/* main.module.css */
.main {
composes: component from "./component.module.css";
color: var(--color-blue);
.nested {
display: block;
}
}
Expected result
I exect to see the styles I include with .main
via `composes: component from "./component.module.css" to be valid (with PostCSS plugins applied). Expected result:
._component_xs2hm_5 {
color: red;
color: var(--color-red);
}
._component_xs2hm_5 ._nested_xs2hm_13 {
width: 100%;
}
._foo_1mrk0_1 {
color: blue;
color: var(--color-blue);
}
._foo_1mrk0_1 ._nested_1mrk0_7 {
width: 100%;
}
Actual result
The styles included via composes
are not processed by PostCSS. They are included in the <style>
tag as-is, resulting in invalid CSS.
._component_xs2hm_5 {
color: var(--color-red);
._nested_xs2hm_13 {
width: 100%;
}
}
._foo_1mrk0_1 {
color: blue;
color: var(--color-blue);
}
._foo_1mrk0_1 ._nested-bar_1mrk0_7 {
width: 100%;
}
The same bug can be observed in the production build.
There was a similar issue logged and fixed in vue-loader
: https://github.com/vuejs/vue-loader/issues/959
Reproduction
https://github.com/elisehein/vite-postcss-compose-repro
System Info
System:
OS: macOS 12.4
CPU: (10) arm64 Apple M1 Pro
Memory: 721.78 MB / 32.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.16.0 - ~/.asdf/installs/nodejs/16.16.0/bin/node
Yarn: 1.22.10 - /usr/local/bin/yarn
npm: 8.15.0 - ~/.asdf/plugins/nodejs/shims/npm
Watchman: 2022.05.16.00 - /usr/local/bin/watchman
Browsers:
Firefox: 103.0.2
Safari: 15.5
Safari Technology Preview: 15.4
npmPackages:
@vitejs/plugin-legacy: ^1.8.2 => 1.8.2
@vitejs/plugin-react: ^1.0.0 => 1.3.2
vite: ^3.0.2 => 3.1.0
Used Package Manager
npm
Logs
No response
Validations
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
Vite puts postcss plugins in the following order.
[postcssImport, postcssModules, ...userPlugins, postcssViteRewriteUrl]
In this order ([postcssModules, postcssNested]
), the output is:
._component_8abi2_1 {
color: var(--color-red);
._nested_8abi2_7 {
width: 100%;
}
}
._foo_15itx_1 {
color: red;
}
But when the order is [postcssNested, postcssModules]
, the output is:
._component_8abi2_1 {
color: var(--color-red);
}._component_8abi2_1 ._nested_8abi2_7 {
width: 100%;
}._foo_15itx_1 {
color: red;
}
So I think we need an option to apply a plugin before default ones, or reorders the plugins.
We had a related PR to change the order of PostCSS plugins, and have the user ones before the internal ones:
- https://github.com/vitejs/vite/pull/7186
In that case, it was closed because the issue should have been fixed upstream. But it could count as another case where having the chance to inject plugins before Vite plugins could have been useful. Maybe we could have a { order: 'pre', ...plugin }
for PostCSS plugins too?
I took a look around postcss plugin specs. Maybe it's possible to solve on plugins' side?
https://github.com/postcss/postcss/releases/tag/8.0.0#:~:text=Plugins%20will%20re%2Dvisit%20changed%20nodes%20to%20reduce%20compatibility%20issues%20between%20plugins.%20Now%20the%20order%20of%20plugins%20in%20your%20PostCSS%20config%20will%20be%20less%20important. #764 #296
I feel it's better to avoid extending the plugin interface of PostCSS.
Another point in favor of waiting here is that there is a chance we end up replacing PostCSS with LigthingCSS in the future
Another point in favor of waiting here is that there is a chance we end up replacing PostCSS with LigthingCSS in the future
Any news on when this will happen? I'm deciding if it's worth waithing for a fix to this issue or just go with plain old css :)
The current approach with postcss-modules
running as the first plugin seems wrong because postcss doesn't apply user plugins in that case.
Now it's either composes X from '...'
or other plugins, but not both. Or at least composed file must be a native CSS file because it won't be processed anyway.
Precisely, now I can't compose a rule from another module and customize that rule with a custom media query at the same time.
Is there any chance that the issue will be fixed somehow?
@patak-dev LigthingCSS faster then PostCSS and probably LigthingCSS or CSSTree better for minifying and other tasks. But not LigthingCSS or CSSTree have not so many plugins as PostCSS. And LigthingCSS written in rust, plugins for it can be written on JS, but it's harder than PostCSS.
It is unlikely that in the near future it will be possible to completely abandon PostCSS, while there is no support injecting plugins before except this
[postcssImport, postcssModules, ...userPlugins, postcssViteRewriteUrl]
This isuue and #12336 will be relevant.
I've implemented a fix via https://github.com/privatenumber/vite-css-modules (which is getting integrated into Vite core via https://github.com/vitejs/vite/pull/16018).
Testing and feedback will be appreciated!