-
-
Notifications
You must be signed in to change notification settings - Fork 248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Webpack 4 + React + CSS modules stripping all classes from CSS bundle #163
Comments
Same problem here |
One last thing, I had to change the CSS "syntax" to something like this import React from "react";
import styles from "./Component.scss";
export default function Component() {
return <div className={styles["component-container"]}>😴</div>;
} |
I renamed the {Name}.scss file to {Name}.module.scss.Example: Header.scss renamed to Header.module.scss |
webpack: 4.29.6 I had this problem too but I managed to solve it. Its like PurgeCSS *Plugin* is invoked in a intermediate phase when React components still have the original CSS classes names set in JSX while CSS modules classes have the new hashed name. Since PurgeCSS parses every JS/JSX/HTML file extracting from them all used CSS classes names, when it compares these last with the new hashed CSS classes names obviously none of them is used because each name is different from the other and thus all your CSS get purged. To make things work, we will use postcss-loader and @fullhuman/postcss-purgecss. You will need the following packages:
You can also install them as dev dependencies. Obviously you need to eject by running const glob = require('glob-all');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
module.exports = function(webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development';
const isEnvProduction = webpackEnv === 'production';
const shouldUseRelativeAssetPaths = publicPath === './';
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {}
},
{
loader: require.resolve('css-loader'),
options: cssOptions
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
syntax: 'postcss-scss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
}),
require('@fullhuman/postcss-purgecss')({
content: [ paths.appHtml, ...glob.sync(path.join(paths.appSrc, '/**/*.{js,jsx}'), { nodir: true }) ],
extractors: [
{
extractor: class {
static extract(content) {
return content.match(/[\w-/:]+(?<!:)/g) || [];
}
},
extensions: [ 'html', 'js', 'jsx' ]
}
]
}),
require('postcss-normalize')
].filter(Boolean),
sourceMap: isEnvProduction && shouldUseSourceMap
}
}
].filter(Boolean);
if (preProcessor) {
loaders.push({
loader: require.resolve(preProcessor),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap
}
});
}
return loaders;
};
return {
/* {...} */
module: {
rules: [
/* {...} */
{
oneOf: [
/* {...} */
{
test: /\.module\.(scss|sass)$/,
use: getStyleLoaders(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap,
modules: true,
getLocalIdent: getCSSModuleLocalIdent
},
'sass-loader'
)
}
/* {...} */
]
}
/* {...} */
]
},
/* {...} */
};
}; You also need to remove PurgecssPlugin from Webpack plugins list. This code snippet is the piece of my Webpack configuration which is responsible of hashing and purging of CSS. It should work straightforward, I hope I didn't leave any pieces back. P.S. Since I use both Tailwind CSS and SASS to style my HTML, in PurgeCSS configuration I had to write an extractor to prevent Tailwind classes to get purged. You can delete it if you don't need it. Furthermore you can use regular module syntax in your JSX just like this: // @flow
import styles from './Test.module.scss';
import * as React from 'react';
type Props = {};
type State = {};
export default class Test extends React.Component<Props, State> {
render(): * {
return (
<div className={styles.myCssClass}></div>
);
}
} |
Wow, thanks a lot @goldmont for the detailed solution. |
@goldmont How I use your solution in craco.config.js instead of ejecting |
@goldmont Is there a way that using |
@goldmont what about next.js and css module? Is this a good way? |
Thank you very much! @goldmont , I just test your code in my own React App, this is the demo —— webpack.config.js.
And that's my configuration in module.exports = {
module: {
rules:[
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-flexbugs-fixes",
"autoprefixer",
"postcss-preset-env",
[
"@fullhuman/postcss-purgecss", // use @fullhuman/postcss-purgecss
{
content: [
path.join(__dirname, "./public/index.html"), //to match index.html
...glob.sync(
`${path.join(__dirname, "src")}/**/*.jsx`, //to match React JSX files in src/components/*.jsx
{
nodir: true,
}
),
],
},
],
],
},
},
},
],
}
]
}
} |
sorry for ask, i have error
i already reinstall node modules and delete package-lock.json. but still show the error. anyone had this problem? ======================= ii use @goldmont's config but without the class =========================== After irecheck css file, file size minimized. But unused bootstrap class(ex: navbar) is still in the css file. How to solve this? |
Hey. Thanks for the wonderful solution to this problem. I am having (maybe) a related issue. When I use |
I came up with a quick solution - a bit hacky, bet overall super simple to implement! Add this rule:
Then in plugins add this Importing
Adding to webpack
The trick:We set
Where After that we add
NOTES: |
Hi birkankervan have you found any solution for next.js and css module? |
https://github.com/eels/next-purge-css-modules works pretty well |
When using CSS modules with React and Webpack 4, all classes are removed from the CSS bundle.
In the options for
css-loader
, if I havemodules: true
the CSS bundle is totally empty.If I comment that out, the CSS bundle is as expected with all unused classes removed, however the JS bundle no longer has the CSS classes on the component elements.
If I add the SCSS files to the
entry
and do not use CSS modules, the CSS bundle is correct as well.The issue appears to be when combining
modules: true
and purgecss.The same is true is I do not use
mini-css-extract-plugin
and let the CSS go into the bundle.Here is my Webpack config:
Here is the entry:
The text was updated successfully, but these errors were encountered: