Frameworks like Bootstrap or Tailwind tend to come with a lot of CSS. Often you use only a small part of it and if you aren't careful, you will bundle the unused CSS.
PurgeCSS is a tool that can achieve this by analyzing files. It walks through your code and figures out which CSS classes are being used as often there is enough information for it to strip unused CSS from your project. It also works with single page applications to an extent.
Given PurgeCSS works well with webpack, we'll demonstrate it in this chapter.
To make the demo more realistic, let's install Tailwind to the project.
npm add tailwindcss postcss-loader --develop
To load Tailwind, we'll have to use PostCSS:
webpack.parts.js
exports.tailwind = () => ({
loader: "postcss-loader",
options: {
postcssOptions: { plugins: [require("tailwindcss")()] },
},
});
The new configuration still needs to be connected:
webpack.config.js
const cssLoaders = [parts.tailwind()];
const commonConfig = merge([
...
parts.extractCSS(),
parts.extractCSS({ loaders: cssLoaders }),
]);
To make the project aware of Tailwind, import
it from CSS:
src/main.css
@tailwind base;
@tailwind components;
/* Write your utility classes here */
@tailwind utilities;
body {
background: cornsilk;
}
You should also make the demo component use Tailwind classes:
src/component.js
export default (text = "Hello world") => {
const element = document.createElement("div");
element.className = "rounded bg-red-100 border max-w-md m-4 p-4";
element.innerHTML = text;
return element;
};
If you run the application (npm start
), the "Hello world" should look like a button.
Building the application (npm run build
) should yield output:
⬡ webpack: Build Finished
⬡ webpack: asset main.css 1.99 MiB [emitted] [big] (name: main)
asset index.html 237 bytes [compared for emit]
asset main.js 193 bytes [emitted] [minimized] (name: main)
Entrypoint main [big] 1.99 MiB = main.css 1.99 MiB main.js 193 bytes
orphan modules 261 bytes [orphan] 2 modules
code generated modules 309 bytes (javascript) 1.99 MiB (css/mini-extract) [code generated]
./src/index.js + 1 modules 309 bytes [built] [code generated]
css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./src/main.css 1.99 MiB [code generated]
As you can see, the size of the CSS file grew, and this is something to fix with PurgeCSS.
purgecss-webpack-plugin allows you to eliminate most of the CSS as ideally we would bundle only the CSS classes we are using.
npm add glob purgecss-webpack-plugin --develop
You also need to configure as below:
webpack.parts.js
const path = require("path");
const glob = require("glob");
const PurgeCSSPlugin = require("purgecss-webpack-plugin");
const ALL_FILES = glob.sync(path.join(__dirname, "src/*.js"));
exports.eliminateUnusedCSS = () => ({
plugins: [
new PurgeCSSPlugin({
paths: ALL_FILES, // Consider extracting as a parameter
extractors: [
{
extractor: (content) =>
content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [],
extensions: ["html"],
},
],
}),
],
});
For exceptions, PurgeCSS 3.0 includes safelist and blocklist options.
Next, the part has to be connected with the configuration:
webpack.config.js
const productionConfig = merge();
const productionConfig = merge([parts.eliminateUnusedCSS()]);
If you execute npm run build
now, you should see something:
⬡ webpack: Build Finished
⬡ webpack: asset main.css 7.68 KiB [emitted] (name: main)
asset index.html 237 bytes [compared for emit]
asset main.js 193 bytes [compared for emit] [minimized] (name: main)
Entrypoint main 7.87 KiB = main.css 7.68 KiB main.js 193 bytes
orphan modules 261 bytes [orphan] 2 modules
code generated modules 309 bytes (javascript) 1.99 MiB (css/mini-extract) [code generated]
./src/index.js + 1 modules 309 bytes [built] [code generated]
css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[0].use[2]!./src/main.css 1.99 MiB [code generated]
webpack 5.5.0 compiled successfully in 2429 ms
The size of the style has decreased noticeably. Instead of 1.99 MiB, we have roughly 7 KiB now.
Tailwind includes PurgeCSS out of the box and it can be preferable to use that. See Tailwind documentation for more information. The example above is enough to illustrate the idea, and it works universally.
uncss is a good alternative to PurgeCSS. It operates through PhantomJS and performs its work differently. You can use uncss itself as a PostCSS plugin.
The idea of critical path rendering takes a look at CSS performance from a different angle. Instead of optimizing for size, it optimizes for render order and emphasizes above-the-fold CSS. The result is achieved by rendering the page and then figuring out which rules are required to obtain the shown result.
critical-path-css-tools by Addy Osmani lists tools related to the approach.
Using PurgeCSS can lead to a significant decrease in file size. It's mainly valuable for static sites that rely on a massive CSS framework. The more dynamic a site or an application becomes, the harder it becomes to analyze reliably.
To recap:
In the next chapter, you'll learn to autoprefix. Enabling the feature makes it more convenient to develop complicated CSS setups that work with older browsers as well.
This book is available through Leanpub (digital), Amazon (paperback), and Kindle (digital). By purchasing the book you support the development of further content. A part of profit (~30%) goes to Tobias Koppers, the author of webpack.