Remove unused CSS with PurgeCSS

We can tackle web performance in different ways, and one of them is removing all JS and CSS we don't use in our apps.

In the case of CSS, it's even more important when we use frameworks such as Bootstrap, Bulma or Tailwind, as well as when we're facing large or legacy applications.

PurgeCSS is a tool that removes unused CSS by applying string comparison. That has some advantages, but also some caveats, so please keep attention to the white-listing part later.

As an example, VueDose's website is built on Nuxt (static generated) using Tailwind, and it uses PurgeCSS to optimize the generated CSS.

If I disable PurgeCSS, you can see that the tailwind css is 485 KB:

While if I activate it, it goes down to 16 KB:

PurgeCSS configuration can be different in each project. It can be set as a webpack plugin or a postcss plugin.

In the case of VueDose, I'm using it as a postcss plugin. So I have a postcss.config.js file with this content:

const purgecss = require("@fullhuman/postcss-purgecss");

const plugins = [...];

if (process.env.NODE_ENV === "production") {
  plugins.push(
    purgecss({
      content: [
        "./layouts/**/*.vue",
        "./components/**/*.vue",
        "./pages/**/*.vue"
      ],
      whitelist: ["html", "body"],
      whitelistPatternsChildren: [/^token/, /^pre/, /^code/],
    })
  );
}

module.exports = { plugins };

Basically, all you need is to tell where to look for the matching classes using the content property.

Also, you'd like to whitelist some classes or tags to don't be removed. You'll need to do that at least in html and body, as well as any dynamic classes.

In my case, I use prismjs in order to highlight the code blocks, and it adds several token classes, as well as styles in the pre and code tags. In order to exclude them, I need to use the whitelistPatternsChildren property.

Tailwind, additionally, needs a custom extractor in order to work properly with PurgeCSS. All in all, the whole postcss.config.js file for VueDose has the following content:

const join = require("path").join;
const tailwindJS = join(__dirname, "tailwind.js");
const purgecss = require("@fullhuman/postcss-purgecss");

class TailwindExtractor {
  static extract(content) {
    return content.match(/[A-Za-z0-9-_:\/]+/g) || [];
  }
}

const plugins = [require("tailwindcss")(tailwindJS), require("autoprefixer")];

if (process.env.NODE_ENV === "production") {
  plugins.push(
    purgecss({
      content: [
        "./layouts/**/*.vue",
        "./components/**/*.vue",
        "./pages/**/*.vue"
      ],
      whitelist: ["html", "body"],
      whitelistPatternsChildren: [/^token/, /^pre/, /^code/],
      extractors: [
        {
          extractor: TailwindExtractor,
          extensions: ["html", "vue"]
        }
      ]
    })
  );
}

module.exports = {
  plugins
};

That's it for today!

Don't miss out anything about Vue, your favourite framework.

Subscribe to receive all the articles we publish in a concise format, perfect for busy devs.

Related Articles

Achieve Max Performance loading your images with v-lazy-image

Don't you know what to do to improve your web performance? Learn Progressive Image Loading, a technique used by Spotify, Medium and Netflix.

Alex Jover Morales

Alex Jover Morales

Aug 30, 2021

Use Responsive Images with v-lazy-image

Is Web Performance a priority for you? Then read this article! You'll learn how to lazy load images with srcset and picture tag using v-lazy-image.

Alex Jover Morales

Alex Jover Morales

Aug 23, 2021

Use Web Workers in your Vue.js Components for Max Performance

Learn how to get up to 20x performance improvement of Vue.js components that rely on heavy tasks so they render and load faster

Alex Jover Morales

Alex Jover Morales

Mar 31, 2020

Sponsors

VueDose is proudly supported by its sponsors. If you enjoy it, consider supporting it to ensure the project maintainability.

Silver
Learning Partner