DEV Community

PostCSS with CSS Modules and React

Dave Irvine on June 14, 2018

Updates 05/07/20 - The localIdentName property for css-loader is now a sub-property of the modules property. 02/10/18 - Looks like Cr...
Collapse
 
roblevintennis profile image
Rob Levin

I really love that I found your article which still seems to work (these things are so damn timely haha). I do find the ident thingy super duper frustrating. I'm utilizing css modules composes and for just two classes btn btn-primary it's resulting in src-components-___base__button___3KDTY src-components-___base__btn___1Fsux which is ridonkulous to read.

Also, I don't know that I understand the whole styleName thing. Is that required? I seem to be fine leaving className.

Anyway, thanks for the step by step!

Collapse
 
daveirvine profile image
Dave Irvine

See my other comments for more on styleName, but you don't have to use it, it can exist alongside className or be ignored entirely. :)

Collapse
 
roblevintennis profile image
Rob Levin

Gotcha thanks

Collapse
 
niksajanjic profile image
Nicky Jay

Hi,

This is a great tutorial, but I think you have an issue in your code. You see, you can't use postcss-import with CSS modules without creating a whole bunch of duplicates. Every file in which you import your colors.css gets inlined which creates a bunch of duplicate :root statements in your final CSS.

You can see more in this issue: github.com/postcss/postcss-import/...

Collapse
 
daveirvine profile image
Dave Irvine

Hi, thanks for the feedback! Yes it looks like duplicate roots are definitely an issue, unfortunately as far as I can tell there is no current way around it?

Collapse
 
niksajanjic profile image
Nicky Jay

There isn't an official or suggested way around it, as far as I know, while I was dealing with this problem. But there are some workarounds. I'm using postcss-preset-env and there's an importFrom option. There you can load a file with variables which are going to be provided for each file, so there's no need to import them manually.

Downside is that you can only import .css, .js or .json. Which is unfortunate if you're using something like SASS, LESS or simply different syntax like SugarSS. So you have to keep variables in different file type than all the others. When it comes to mixins, they don't get injected so I import them per file.

Another possibility is to use one of the deduplication plugins provided.

Last one I can think of is just use postcss-simple-vars, instead of :root and native CSS variables.

Although I was using variables like this plugin supports, I like to use native CSS variables when they're supported, even though I like plugin syntax better.

Hope this helps as bit.

Collapse
 
daveirvine profile image
Dave Irvine • Edited

So styleName comes from the babel-plugin-react-css-modules plugin. Stolen from their docs:

However, there are several several disadvantages of using CSS modules this way:

  • You have to use camelCase CSS class names.
  • You have to use styles object whenever constructing a className.
  • Mixing CSS Modules and global CSS classes is cumbersome.
  • Reference to an undefined CSS Module resolves to undefined without a warning.

Using babel-plugin-react-css-modules:

  • You are not forced to use the camelCase naming convention.
  • You do not need to refer to the styles object every time you use a CSS Module.
  • There is clear distinction between global CSS and CSS modules, e.g.
<div className='global-css' styleName='local-module'></div>
Collapse
 
gsaran profile image
gsaran

Hi,

Thanks for the great tutorial.
I have the configurations as explained in the tutorial but still css files are throwing error:

Module build failed (from ../node_modules/postcss-loader/src/index.js):
Error: Cannot find module 'react-css-modules'

webpack.config.js:

{
test: /.css$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
options: {
modules: {
localIdentName: '[name]__[local]--[hash:base64:5]',
},
sourceMap: true,
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
},
],
},

postcss.config.js:

plugins: [
require('postcss-inline-svg'),
require('postcss-import'),
require('postcss-pxtorem')({...}),
require('postcss-mixins')({...}),
require('react-css-modules'),
require('postcss-color-gray'),
require('postcss-preset-env')({
browserslist: [...],
stage: 3,
features: {
'custom-properties': {
preserve: false,
},
'nesting-rules': true,
'color-mod-function': { unresolved: 'warn' },
},
}),
require('postcss-extend'),
],

.bablerc:

"plugins": ["@babel/plugin-proposal-object-rest-spread", "lodash",
["react-css-modules", {
"webpackHotModuleReloading": true,
"exclude": "node_modules",
"generateScopedName": "[name]__[local]--[hash:base64:5]"
}
]
],

Any idea what's going wrong here?

Collapse
 
daveirvine profile image
Dave Irvine

Looks like you've got 'react-css-modules' as a plugin in your PostCSS config? It doesn't belong there, its just a Babel plugin.

Collapse
 
gsaran profile image
gsaran

Thanks!! It worked.

Collapse
 
iskin profile image
Andrey Sitnik

BTW, CSS Modules is just a bunch of PostCSS plugins inside

Collapse
 
daveirvine profile image
Dave Irvine

👍 Didn't know that! Perhaps I should retitle post: "Other PostCSS plugins with CSS Modules and React"?

Collapse
 
iskin profile image
Andrey Sitnik

The article name is great ☺. It is just a curious fact.

BTW, css-loader is PostCSS plugins too 😄.