LighthousePurgeCSSNextJSNodeJSTech

Using purgecss to increase Lighthouse speed drastically when using NextJS and Antd

WarningOnly available in the original language

05.07.2021

Using purgecss to increase Lighthouse speed drastically when using NextJS and Antd

Optimizing your page for Google's Lighthouse Score (PageSpeed Insights) can be quite a hassle. Here's how we improved it from the mid 30s range to (at least) the 80s range.

We've spent hours and hours trying to reduce NextJS' bundle size, initial JS size. One aspect we've tried was importing all the components in a direct way, without tree-shaking:

// Instead of
import { Layout } from 'antd'

// We've rewritten every single component to direct imports
import Layout from 'antd/lib/layout';

As it turned out, that didn't help. It seemed like tree shaking was working already.

Another tip found on the internet was to use dynamic imports for your components. So we've tried and used them in every possible place:

// Non-dynamic
import Footer from "./Layout/Footer";

// Dynamic
const Footer = dynamic(() => import('./Layout/Footer'))

This, at least, reduced NextJS' initial JS chunk size. But it didn't do much to improve our Lighthouse Score.

After trying countless other things, like different Webpack plugins, babel presets, minifiers and so on, what finally worked like a charm for us was PurgeCSS.

Our initial CSS file was around ~500kb (yes, combining Bootstrap with Antd is not the best idea).

PurgeCSS enabled us to reduce our CSS size to around ~140kb (unzipped), which is a lot!

However, this comes with a price. We needed to add a lot of classes manually to our whitelist because PurgeCSS doesn't seem to work very well with NextJS' HTML.

Now, our PurgeCSS configuration looks like this:

// purge.js

const {PurgeCSS} = require('purgecss')
const fs = require("fs")

new PurgeCSS().purge({
    content: ['.next/**/*.html'],

    safelist: {
        standard: [
            /^ant-modal-.*/, /^ant-click-.*/, /^ant-zoom-.*/ // ... and many many more. Beware of just adding /^ant-.*/ as this will still keep a lot of CSS
        ]
    },

    css: ['.next/**/*.css'],
}).then(res => {
    res.map(file => {
        fs.writeFileSync(file.file, file.css, {encoding: 'utf8', flag: 'w'})
        console.log("[X] Writing " + file.file)
    })
})

Adding it to our build process works like a charm:

// package.json
 "scripts": {
    "dev": "next dev",
    "build": "NODE_ENV=production next build && node purge",
    "start": "next start -p 8080"
  },

Maybe this approach helps you too. Good luck. It can also be integrated with PostCSS when using NextJS.

With the reduced CSS, our website does now achieve a much better score. It's not yet perfect and there's still room for improvement. But still, this is a lot better.