I’m trying to create a new theme for Hugo.

Hugo offers powerful features, for example, Hugo pipes. Pipes allow you to transform data in your Hugo templates.

I want to use PurgeCSS to remove unused CSS from my production bundle.

The official website has a guide for using PostCSS with Hugo, but it was not 100% clear to me how to use the instructions.

1. Template

You will have a html template in your themes folder. Mine has the folllowing path: themes/<name-of-theme>/layouts/partials/head.html:

{{- $critical := resources.Get "scss/critical.scss" | resources.ToCSS }}
{{- $fonts := resources.Get "scss/fonts.scss" | resources.ToCSS | resources.Minify | resources.Fingerprint }}
{{- if hugo.IsProduction }}
{{- $critical = resources.Get "scss/critical.scss" | resources.ToCSS |  resources.PostProcess | resources.Minify | resources.Fingerprint }}
{{- end }}
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <link rel="stylesheet" href="{{ $critical.RelPermalink }}" />
  <link rel="stylesheet" media="print" href="{{ $fonts.RelPermalink }}" onload="this.media='all'" />
  <title>
    {{ if not .IsHome }}{{ with .Title }}{{ . }} | {{ end }}{{ end }}{{
    .Site.Title }}
  </title>
  <meta
    name="description"
    content="{{ with .Description }}{{ . }}{{ else }}{{ with .Summary }}{{ . }}{{ else }}{{ .Site.Params.description }}{{end }}{{ end }} "
  />
  {{ template "_internal/opengraph.html" . }}
  {{ template "_internal/twitter_cards.html" . }}
  {{ template "_internal/schema.html" . }}
</head>

If we make a production build with the command hugo, we will process the Sass SCSS file with several transformations.

2. Main Folder

The above code sits in the theme folder, nested in your main Hugo project.

Example folder structure:

├── archetypes
│   └── default.md
├── config.toml
├── content
│   ├── about.md
│   └── blog
│       ├── 2021
│       │   ├── hipsum.md
│       │   └── lorem-ipsum.md
│       └── _index.md
├── data
├── layouts
├── static
└── themes
    └── sample-hugo-theme
        ├── archetypes
        │   └── default.md
        ├── assets
        │   └── scss
        │       ├── _config.scss
        │       ├── critical.scss
        │       └── _reset.scss
        ├── layouts
        │   ├── 404.html
        │   ├── blog
        │   │   └── single.html
        │   ├── _default
        │   │   ├── about.html
        │   │   ├── baseof.html
        │   │   ├── list.html
        │   │   └── single.html
        │   ├── index.html
        │   └── partials
        │       ├── footer.html
        │       ├── header.html
        │       ├── head.html
        │       ├── page-header.html
        │       ├── pagination.html
        │       └── post_pagination.html
        ├── LICENSE
        └── theme.toml

We run the necessary commands from the main folder. For development mode, we use hugo server, for production mode, we use hugo.

Depending on which command you run, Hugo will recognize the mode.

That means that you’ll need to set configuration settings from guide in the main folder (not the themes folder where your HTML template resides).

Install the necessary Node.js dependencies in the main Hugo directory (same folder as config.{toml,yaml,json}:

npm i -D @fullhuman/postcss-purgecss postcss postcss-cli

The next parts are identical to the documentation:

Adjust the configuration. If you use toml, here’s the example config.toml:

[build]
  writeStats = true

Create a postcss.config.js:

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

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

3. Production Build

Run the following command inside your terminal:

hugo

The command will create a public folder which contains the static website that you built with Hugo. Your CSS assets should work.

Thoughts

If you share your theme for others to use, they will have to go through the steps of installing the Node.js dependencies in their Hugo project.

I find that less than ideal, as I prefer to manage my assets from the themes folder.