Skip to content
Working example of tree shaking CSS modules
JavaScript CSS HTML
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
.babelrc
.gitignore
README.md
index.html
package.json
webpack.config.js
yarn.lock

README.md

CSS Modules with Tree Shaking

This repo shows how to use css-modules (with css-loader) and tree shake any used imports from both the outputted CSS file as well as the js bundle.

Quick Reference

You will need to have the following dependencies installed:

yarn add @fullhuman/postcss-purgecss \
         css-loader \
         cssnano \
         mini-css-extract-plugin \
         node-sass \
         postcss-loader \
         postcss-scss \
         sass-loader \
         style-loader

Here is the webpack config for quick reference:

/* eslint-env node */

const path = require('path')
const glob = require('glob')
const webpack = require('webpack')

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

const entry = filename => [path.resolve(__dirname, filename)]

module.exports = {
  mode: 'production',

  entry: entry('src/index.js'),

  output: {
    filename: '[name].js',
    path: path.resolve('dist'),
  },

  resolve: {
    extensions: ['.js'],
  },

  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.s?css$/,
        exclude: /node_modules/,
        use: [
          // Extract the css to file
          MiniCssExtractPlugin.loader,
          { 
            loader: require.resolve('css-loader'), 
            options: { 
              // Enable CSS modules
              modules: {
                // Specify format of class names
                localIdentName: '[local]_[hash:base64:5]'
              },
            } 
          },
          {
            loader: require.resolve('postcss-loader'),
            options: {
              indent: 'postcss',
              syntax: 'postcss-scss',
              plugins: () => [
                // Purge unused CSS
                require('@fullhuman/postcss-purgecss')({
                  content: glob.sync('src/**/*.{js,jsx}', { nodir: true }),
                  extractors: [
                    {
                      extractor: class {
                        static extract(content) {
                          // NOTE: this regex needs work. At the moment it simply matches any keyword that matches a class name. If you were to have a class name "alert" and create a react component with a text body that has the word "alert" in it, it would result in the alert className being unnecessarily imported.
                          return content.match(/\w+/g) || [];
                        }
                      },
                      extensions: ['js', 'jsx' ]
                    }
                  ]
                }),
                require('cssnano')
              ]
            }
          },
          require.resolve('sass-loader')
        ],
      },
    ],
  },
  plugins: [
    // Extract all css into a separate file
    new MiniCssExtractPlugin({
      filename: '[name].css',
    }),
  ],
}
You can’t perform that action at this time.