Remove unused css with React and Webpack

15.1k views Asked by At

I'm trying to remove unused css classes from my app using purify-css for WebPack.

To build this project I'm usin React, scss, WebPack and PostCss to build and compile everything.

So far I was able to have progress, but there is something wrong and I don't know why, but the expected result isn't correct. I have a very very basic setup just to test these scenarios, so this is my index.html and app.js files (the only files I have so far):

index.html

<body>
    <nav>
        <a href="">home</a>
    </nav>
    <hr />
    <div id="app"></div>
    <footer class="my-other-heading"></footer>
</body>

app.js

class App extends React.Component {
    render() {
        return (
            <h1 className="my-other-heading">Mamamia!</h1>
        );
    }
}

render(<App />, window.document.getElementById("app"));

On the css files I'm using Normalize.css (with a bunch of css classess) and just 3 custom classes:

.my-class {
    background-color: #CCDDEE;
}

.my-heading {
    color: red;
}

.my-other-heading {
    color: blue;
}

The expected output should contain only these classes:

html, body, nav, a, hr, div, footer, h1, .my-other-heading

However it has some other classes:

.my-heading, h2, h3, h4, [type='checkbox'] (and other similar, e.g.: [type='button']

Why is this happening? It's removing almost all the classes it should, but some of them are still here, and classes that are clearly not being used on the index file. I don't know if they persist because of some other declaration on the React side, but i'm refering only the src files. This is my purify-css config:

new PurifyCSSPlugin({
  paths: glob.sync([
    path.join(__dirname, '..', 'src', '**/*.html'),
    path.join(__dirname, '..', 'src', '**/*.js'),
  ]),
})
2

There are 2 answers

0
Jorge C On

You can try this webpack.config sample, It strips all unused classes from CSS and SASS files, however, it adds classes from normalize.css

  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader',
          publicPath: '/dist'
        })
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader'],
          publicPath: '/dist'
        })
      },  
...
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Webpack2 - purify css',
      minify: {
        collapseWhitespace: true,
      },
      hash: true,
      template: './src/index.html'
    }),
    new ExtractTextPlugin({
      filename: '[name].css',
      disable: false,
      allChunks: true
    }),
    new PurifyCSSPlugin({
      paths: glob.sync(path.join(__dirname, 'src/*.html')),
      purifyOptions: { info: true, minify: false }
    }), 
...
1
xurei On

From my own experience (15+ in Web dev), trying to remove CSS automatically always bring more problem than it solves.

Classnames can change over runtime, sometimes in an unexpected way. Automating the removal of CSS is somewhat equivalent to the Halting Problem : not solvable in general, nor reliable in particular.

I don't know the reason why you don't get the classes that should obviously be there. But I don't think you should try to do that in the first place.

The best/only solution to me so far is to do it manually, and try to keep it clean.

I realize that it might not be the answer you are looking for.