Hugo

Hugo is one of the most popular open-source static site generators. With its amazing speed and flexibility, Hugo makes building websites fun again.

PurgeCSS can be used with Hugoopen in new window via Hugo Pipes asset processing.

Tooling

  1. Install Hugoopen in new window
  2. Install Node.jsopen in new window

Write Stats

In your config.toml file, add this:

[build]
  writeStats = true

Or, If using a config.yaml file, add this:

build:
  writeStats: true

This tells Hugo to write a hugo_stats.json file to the project root as part of the build. It includes all tags, classes, and ids from your *.html templates.

Node Packages

If the package.json file at the project root doesn't exist yet (which tracks all your node dependancies), run this command from your project root directory to create it:

npm init

You can enter as much or little information as you want. When the file is created, you can continue to install the packages.

Run this from your project root to install the necessary packages:

npm install postcss postcss-cli @fullhuman/postcss-purgecss --save

The packages will install into a folder called node_modules and also be added to your package.json file.

If it's not already there, add node_modules/ to your .gitignore file.

PostCSS Config File

Create a postcss.config.js file at the project root with these contents:

const purgecss = require("@fullhuman/postcss-purgecss")({
  content: ["./hugo_stats.json"],
  defaultExtractor: (content) => {
    const els = JSON.parse(content).htmlElements;
    return [...(els.tags || []), ...(els.classes || []), ...(els.ids || [])];
  },
  safelist: [],
});

module.exports = {
  plugins: [
    ...(process.env.HUGO_ENVIRONMENT === "production" ? [purgecss] : []),
  ],
};

See the PurgeCSS configuration docs for details on each option.

Note: safelist is an empty array (for now). Remember, only elements from your HTML templates are extracted. So, if your JS adds elements, you'll need to safelist them.

HTML Template

In the HTML Template for your <head>, add this:

{{ $css := resources.Get "css/style.css" | resources.PostCSS }} 
{{ if hugo.IsProduction }} 
    {{ $css = $css | minify | fingerprint | resources.PostProcess }} 
{{ end }}

<link
  rel="stylesheet"
  href="{{ $css.RelPermalink }}"
  {{ if hugo.IsProduction -}} 
    integrity="{{ $css.Data.Integrity }}"
  {{- end }}
/>

This assumes:

  • Your CSS file is at assets/css/style.css
  • You want to minify and fingerprint the production version of this file

If these assumptions aren't true for you, modify the code accordingly.

Use it

Cool, now we can use it.

Serve your site in development mode, which is the default:

hugo serve

Open your browser DevTools, go to the Network tab, then note the size of the CSS file.

Now, Control + C to stop it, then serve your site in production mode:

hugo serve --environment production

Notice the CSS file now has a much smaller size.

Environment

If you don't want to pass the --environment production option, you can set this env var:

HUGO_ENVIRONMENT=production

References