Reputation: 1646
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';
Upvotes: 4
Views: 2350
Reputation: 41579
Update (in 2024):
The documentation for css loader getLocalIdent has:
Allows to specify a function to generate the classname. By default we use built-in function to generate a classname. If the custom function returns null or undefined, we fallback to the built-in function to generate the classname.
So a custom getLocalIdent function can perform the required filter to choose to return localName
, and then just return null to fall back to the built in function.
Updating @GasaiYuno's second answer then:
getLocalIdent: (loaderContext, localIdentName, localName, options) => {
return loaderContext.resourcePath.includes('semantic-ui-css') ?
localName :
null;
}
Upvotes: 0
Reputation: 5475
Updated solution from playing771
{
loader: 'css-loader',
options: {
modules: {
auto: (resourcePath) => !resourcePath.includes('node_modules'),
localIdentName: '[name]__[local]__[hash:base64:5]',
},
},
},
Upvotes: 2
Reputation: 8273
For me using :global
worked :
.my-component {
:global {
.external-ui-component {
padding: 16px;
// Some other styling adjustments here
}
...
}
}
Ps: for doing it with webpack config, please see another answer.
Upvotes: 4
Reputation: 51
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);
}
}
}
Upvotes: 5