blabbath
blabbath

Reputation: 462

webpack PurgeCSS webpack Plugin not working as expected

I want to purge unused CSS from the Clarity UI CSS file, in a setup using webpack and purgecss-webpack-plugin.
However, while the size of the CSS file is reduced from 565kB to 172kB, it should be reduced to 0kB since I don't use any of it. If I do the same thing using Bootstrap, the filesize is reduced to 1kB.

Why is that behaviour and is there a fix?

My folder structure is as follows:

|-dist  
|  
|-node_modules  
|  
|-src  
  |--index.js  
|  
|.babelrc  
|package.json  
|webpack.config.js 

My package.json:

{
  "name": "webpack-clarity",
  "version": "1.0.0",
  "description": "",
  "private": true,
  "scripts": {
    "start": "node ./index.js",
    "build": "webpack"
  },
  "dependencies": {
    "@clr/ui": "^4.0.0",
    "bootstrap": "^4.5.2"
  },
  "devDependencies": {
    "@babel/core": "^7.10.4",
    "@babel/preset-env": "^7.10.4",
    "babel-loader": "^8.1.0",
    "css-loader": "^3.6.0",
    "glob": "^7.1.6",
    "html-webpack-plugin": "^4.3.0",
    "mini-css-extract-plugin": "^0.9.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "purgecss-webpack-plugin": "^2.3.0",
    "webpack": "^4.44.1",
    "webpack-cli": "^3.3.12"
  }
}    

webpack.config.js

const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const glob = require("glob");
const PurgeCSSPlugin = require("purgecss-webpack-plugin");

module.exports = {
  mode: "production",
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
  },
  optimization: {
    minimizer: [new OptimizeCssAssetsPlugin(), new TerserPlugin()],
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader"],
      },
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
    ],
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: "[name].css" }),
    new PurgeCSSPlugin({
      paths: glob.sync("./src/**/*.js", { nodir: true }),
    }),
  ],
};

.babelrc

{
  "presets": [
    [   
      "@babel/preset-env",
      {"modules": false}
    ]
  ]
}

index.js

import "../node_modules/@clr/ui/clr-ui.min.css";
import "../node_modules/bootstrap/dist/css/bootstrap.min.css";

Upvotes: 0

Views: 3511

Answers (1)

andreivictor
andreivictor

Reputation: 8491

A little bit late with this answer, but maybe it will help.

TLDR: PurgeCSS only removes unused CSS classes by default. We need to enable PurgeCSS to also remove unused CSS variables, keyframes & font-face declarations.

Add the following options for PurgeCSSPlugin:

{
  paths: glob.sync("./src/**/*.js", { nodir: true }),

  // add the following options
  fontFace: true,
  variables: true,
  keyframes: true,
}

Details:

Considering that in src/index.js we only import Clarity UI CSS file:

import "../node_modules/@clr/ui/clr-ui.min.css";

let's take a look at the compiled CSS file (dist/[name].css]). It has ~175 kb and it contains:

  • CSS variables defined in Clarity UI Framework
  • animation declarations (keyframes)
  • @font-face font-family: "Metropolis" declarations with the font source inlined as a base64 string

To make PurgeCSS to also remove unused CSS variables, keyframes & font-face declarations, we need to add the following options:

new PurgeCSSPlugin({
  paths: glob.sync("./src/**/*.js", { nodir: true }),

  // add the following options
  fontFace: true,
  variables: true,
  keyframes: true,
}),

The compiled CSS file now has ~117kb.

Since the html and body tags have set a font declaration in ClarityUI CSS file, PurgeCSS will not remove @font-face declarations:

html {
font-family:Metropolis,"Avenir Next","Helvetica Neue",Arial,sans-serif;
font-family:var(--clr-font, Metropolis, "Avenir Next", "Helvetica Neue", Arial, sans-serif);
}

Tested with:

"@clr/ui": "^4.0.16"
"webpack": "^5.89.0",
"purgecss-webpack-plugin": "^5.0.0",

From the PurgeCSS docs:

  • fontFace (default: false)

If there are any unused @font-face rules in your css, you can remove them by setting the fontFace option to true.

  • keyframes (default: false)

If you are using a CSS animation library such as animate.css, you can remove unused keyframes by setting the keyframes option to true.

  • variables (default: false)

If you are using Custom Properties (CSS variables), or a library using them such as Bootstrap, you can remove unused CSS variables by setting the variables option to true.

Upvotes: 1

Related Questions