I am trying CSS Modules for the first time with React and Webpack and I came across at least three ways to achieve it:
I went with babel-plugin-react-css-modules in order to balance code simplicity and performance and everything seems to be working fine except for one thing: my 3rd party libraries (Bootstrap and Font Awesome) are also included in CSS Modules transformation.
<NavLink to="/about" styleName="navigation-button"></NavLink>
The above assigns a properly transformed className to the NavLink. However, a span inside needs to refer to global styles in order to render an icon.
<span className="fa fa-info" />
The above span is not assigned a transformed className which is expected, but my bundled stylesheet does not have these CSS classes as they are being transformed into something else, to simulate local scope.
Below is the content in my .babelrc file to activate babel-plugin-react-css-modules:
{
"presets": ["env", "react"],
"plugins": [
["react-css-modules", {
"generateScopedName": "[name]__[local]___[hash:base64:5]",
"filetypes": {
".less": {
"syntax": "postcss-less"
}
}
}]
]
}
In my Webpack configuration, below is the section to configure css-loader for transforms:
{
test: /\.(less|css)$/,
exclude: /node_modules/,
use: extractCSS.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
minimize: true,
modules: true,
sourceMap: true,
localIdentName: '[name]__[local]___[hash:base64:5]'
}
},
{
loader: 'less-loader'
}
]
})
}
As far as I have read, the above rule should exclude the library stylesheets and I also tried adding another rule specifically for the excluded stylesheets, however that did not seem to work, as I guess as those stylesheets were still transformed with the original rule.
In order to import CSS from the two libraries, I have the below two lines in my parent stylesheet that declares some global styles:
@import '../../../node_modules/bootstrap/dist/css/bootstrap.min.css';
@import '../../../node_modules/font-awesome/css/font-awesome.min.css';
I find these two approaches below might be helpful:
In short, there seems to be no options to ignore/exclude certain paths from being modularized by the css-modules webpack plugin so far. Ideally it should be supported by the plugin, but here're some approaches you can try out:
use two webpack rules to utilise the webpack rule exclusion/inclusion:
module.exports = {
rules: [
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path]__[local]___[hash:base64:5]',
},
},
],
},
{
test: /\.css$/,
include: /node_modules/,
use: ['style-loader', 'css-loader']
}
]
}
...or, inject into webpack's getLocalIdent from the second answer above to manually exclude certain paths.
const getLocalIdent = require('css-loader/lib/getLocalIdent');
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]',
getLocalIdent: (loaderContext, localIdentName, localName, options) => {
return loaderContext.resourcePath.includes('semantic-ui-css') ?
localName :
getLocalIdent(loaderContext, localIdentName, localName, options);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With