babel-plugin-react-css-modules
babel-plugin-react-css-modules copied to clipboard
Implement a "SCSS preset" supporting all standard SCSS features out of the box (those for which just postcss-scss is not enough)
Hi, I have trouble making the plugin work with Webpack 5 + SCSS. I had a working setup with the original gajus/babel-plugin-react-css-modules, Webpack 4, and SCSS. During the migration to Webpack 5 I had to swap the original plugin for yours (thank you for maintaining the fork!). The configuration remained mostly the same.
I have created a minimalistic example here: https://github.com/vlastimil-dolejs/css-modules-scss-bug
The error I get is:
ERROR in ./src/Test.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
CssSyntaxError: C:\code\css-modules-scss-bug\src\Test.scss:6:4: Expected a pseudo-class or pseudo-element.
at C:\code\css-modules-scss-bug\src\Test.scss:6:3
at Input.error (C:\code\css-modules-scss-bug\node_modules\postcss\lib\input.js:148:16)
at Rule.error (C:\code\css-modules-scss-bug\node_modules\postcss\lib\node.js:60:32)
at Root._error (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:177:25)
at Root.error (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\selectors\root.js:43:19)
at Parser.error (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:740:21)
at Parser.expected (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:1133:19)
at Parser.pseudo (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:875:19)
at Parser.parse (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:1084:14)
at Parser.loop (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:1043:12)
at new Parser (C:\code\css-modules-scss-bug\node_modules\postcss-selector-parser\dist\parser.js:164:10)
@ ./src/index.js 3:0-26 4:50-54
The error is thrown, when there is some special SASS construct in the .scss file. It looks like the class name lookup is done in .scss file before it is processed by postcss-scss
.
Relevant part of babel.config.js
const plugins = [
["@dr.pogodin/react-css-modules", {
"exclude": "node_modules",
"generateScopedName": "[path][name]__[local]",
"filetypes": {
".scss": {
"syntax": "postcss-scss"
}
}
}]
];
Relevant part of webpack.config.js
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
MiniCssExtractPlugin.loader,
{
loader: "css-loader",
options: {
modules: {
localIdentName: "[path][name]__[local]",
},
importLoaders: 1, // to include sass-loader
sourceMap: true,
}
},
"sass-loader"
]
}
Ok. I'll check within next few days.
Hey @vlastimil-dolejs ,
It looks to me the problem in your example is that you are using SASS interpolation syntax in selector name. You have postcss-scss syntax parser configured for SCSS files, but that parser on its own does not compile SCSS instructions, so babel-plugin-react-css-modules still sees .#{$selector-var}
selector rather than .test
you expect it to be, hence the failure.
To make it work with this syntax you should add a PostCSS plugin to transform that syntax, and that plugin must be synchronous. The closest I found is https://github.com/postcss/postcss-simple-vars. I think if you try in the configuration this:
"filetypes": {
".scss": {
"syntax": "postcss-scss"
},
"plugins": ["postcss-simple-vars"],
}
and if you write the selector as .$selector-var
(the interpolation syntax understood by postcss-simple-vars), it will work.
The caveat is sure that to work with the original SASS interpolation syntax you need to find (or write) a slightly different plugin which, at least, transforms selectors like .#{$var}
into just .$var
(if you do this before postcss-simple-vars, then that plugin will take care of the rest).
With this said, I believe it is not a bug in babel-plugin-react-css-modules, and we can close this ticket, as the support of specific SASS syntax pre-compilation is not a part of this project. Sure, if you find / write a PostCSS plugin which solves this problem, I'll be glad to mention it in README of this plugin.
Hi @birdofpreyru,
Thank you for the analysis. I have misunderstood the role of the postcss-scss
syntax. You are correct that without the plugins the syntax reads the content of the scss file but doesn't resolve any dynamic features of the SASS. It's not only the variable interpolation but also some other features. I will probably stick with plain CSS modules without styleName
s.
Thank you!
Just curious, what other features you found causing problems? I'm myself using this plugin with SCSS, and had no issues, as postcss-scss
still covers most of stuff, as long as you don't do something exotic with classnames (e.g. I even didn't know/need before that it is possible to interpolate variable inside classnames, while interpolation inside rule values is fine for this plugin).
I had a problem with:
Property nesting (https://sass-lang.com/documentation/style-rules/declarations#nesting) - this can be solved with postcss-nested-props
but it causes problems with CSS modules :global()
keyword (.my-button:global(.btn) {...}
)
Parent selector used for class composition:
.foo {
&-bar {
}
}
Class .foo-bar
is available only after compilation.
And the already mentioned variable interpolation.
Thanks. It makes me think to pre-assemble a sort of "preset", which is easy to enable and have all standard SCSS features supported out of the box, rather than having to hunt for individual PostCSS plugins for individual features. Not sure I have time to do it in the nearest future.