How To Add HTML Minification To Hugo Deployment Process
Hugo doesn’t currently support HTML minification, but it’s very simple to add it to the deployment process using an external tool. We’re going to use minify by Taco de Wolff, just because it’s written in Go and because it’s insanely fast.
Even after writing this article I have opted not to use this tool yet, because it currently strips out white space from between The issue with
pre tags if they contain other html elements. This is usually the case when there are code snippets that have syntax highlighting, like those created with Pygments. I have a lot of code snippets and it’s essential for their readability that indentation and alignment is preserved. If you don’t have preformatted text in your posts this tool will work fine.
pre tags has been fixed.
If Go isn’t installed on your system, install it first.
$ cd ~ $ curl -O https://storage.googleapis.com/golang/go1.6.2.linux-amd64.tar.gz $ tar -xvf go1.6.2.linux-amd64.tar.gz $ sudo mv go /usr/local
Using your favorite editor, add the following to ~/.profile:
Refresh your profile by running:
$ source ~/.profile
Verify that everything works:
$ go version
The above should print the version number of your Go installation.
Minify is available as a Go library and as a command line tool. We’re going to install the CLI.
First, add these lines to your ~/.profile.
GOPATH is needed to install the packages and we’re adding the
$GOPATH/bin so we can run the Go binaries without using the full path.
export GOPATH=~/go export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
Refresh your profile again:
$ source ~/.profile
Now, install the minify package (you need to have Git installed for this to work, by the way):
$ go get github.com/tdewolff/minify/cmd/minify
Once it’s installed you can minify the .html files on your site by running:
$ minify --recursive --verbose --match=\.*ml /path/to/dir
The above command goes recursively through /path/to/dir directory and minifies all .html and .xml files it finds (and others that match the pattern), giving verbose output while doing so. Since we haven’t specified output directory, it replaces the original HTML files with the minified ones.
Do not use the –type=html switch if you have SVG files in the directory. If the type is set as
html the minifier attempts to minify the SVG files too, but it currently doesn’t handle SVG files very well, meaning it mangles them. If you need to minify SVG files, consider using SVGO for the time being.
Making A Script For Deployment
Instead of typing all that each time, let’s make a very simple script for it.
The directory where the sources of my Hugo site are is hugo . public is the directory for compiled site. You should of course adjust those to reflect your directory structure and make the paths more specific if you place this script somewhere else.
Create a new file (deploy.sh in this example):
#!/bin/sh # Destination directory is relative to the sources # directory, so it's best to give full path hugo -s hugo -d /absolute/path/to/public minify -r -v --match=\.*ml public
Make the file executable so you can run it as a script:
$ chmod +x deploy.sh
After that you can run it by typing:
Did it work? Yes? Great.
Now, let’s automate things a bit, shall we? I mean, wouldn’t it be better if all this happened automatically when files are changed?
Both Hugo and Minify support watching a directory and running when changes occur, but minify supports watching a directory only if it’s different from the output directory, which makes sense. Since Hugo isn’t able to run external scripts after compiling a site, the only choice is to use some other tool to watch for changes and run Hugo and minify separately.
If you’re using Linux you have many choices, but I have tested two: inotifywait and entr. I’m personally using entr, but I’ll show how to use inotifywait, too.
inotifywait is part of inotify-tools and it sits on top of inotify, which is a Linux kernel subsystem. inotify is therefore found on every Linux system, but inotify-tools needs to be installed separately.
$ sudo apt-get install inotify-tools
Then we create a script for it (I named mine stalk.sh):
#!/bin/sh while inotifywait -r -e modify,attrib,close_write,move,create,delete hugo do ./deploy.sh done
Make this one executable, too:
$ chmod +x stalk.sh
You can then run it with ./stalk.sh. You can end the script execution with ctrl-c.
What happens here is that we tell inotifywait to watch the source directory recursively and wait for certain events to take place. When they do, our loop is triggered and the deploy.sh script is run, after which we again wait input from the inotifywait.
“Because the inotifywait command waits for something to happen in the directory, it’s much more efficient than continually polling the directory.” sayeth the wise people at Stack Overflow, so this should be a good solution resource-wise.
One of the disadvantages of inotifywait is that it can miss files that are modified while our script is in the do block, in which case the deploy script might miss them too.
The Event Notify Test Runner is an actively developed “general purpose Unix utility intended to make rapid feedback and automated testing natural and completely ordinary”. It takes a list of files as input and when any of them change runs a given command. It can also monitor a directory for added and deleted files.
On Ubuntu you can install it with apt-get:
$ sudo apt-get install entr
Once entr is installed, create a file and type in the following:
#!/bin/sh while : do find hugo/ -type f | entr -d ./deploy.sh done
Remember to make it executable like previously.
What we’re doing here is repeating the script endlessly. Each time we find all the files in the source directory and pipe them to entr, telling it to also watch the parent directory of each file for added and removed files (
-d) and to execute deploy.sh when changes occur. Note: This script doesn’t notice added directories, only files. It also doesn’t notice if a file has been added to a previously empty directory.
Unlike inotifywait entr waits until the kernel stops sending events and acts only then, so it’s not as likely to miss a series of rapid changes. At least, that’s my understanding.
When I tested these scripts both worked without problems on my very small site. Your mileage may vary, of course.
For more options, see How to execute a command whenever a file changes? at Super User.