Hugo static asset cache busting

Hugo is a great static site generator. It is crazy fast and has tons of options, but one thing I had not been able to discover was how to use variable data in make, my build tool, and pass it to a Hugo template. I wanted a way to create unique CSS filenames, and use those filenames in my Hugo templates.

I have configured my web server to have very long cache time to live on static CSS files. By giving each file a unique name I can clear the client side cache, and be assured that visitors will see the most recent version of my CSS.

As it turns out that Hugo has a template function, getenv , that is used to get data from an environmental variable. This data can then be used in the template; output as part of the template, or used in conditional statements.

Ideally we would have a unique value per CSS file that is used to identify a specific version of our CSS, like the git hash of the file. This would allow visitors to only download CSS files that have changed, but this is the quick and dirty version so we will use just a random number.

Steps

Here is the basic process we will follow:

Generate a random number in make, and put it into a make environmental variable. Export the variable to the build environment. Use getenv to pull the data into the template.

Make

The first thing we need to do is generate a very large random number. We will use this as our version identifier. Let us create a make variable from the output of an awk command that is run in a shell. min and max are the end ranges for our number. We want a large number to cut down on the chance of reuse.

1 RAND_NUM = $( shell awk -v min = 1000000000 -v max = 9999999999 'BEGIN{srand(); print int(min+rand()*(max-min+1))}' )

Next we need to make sure our random number is available in the build environment. Each line of a make recipe is executed in it’s own shell. We can not just add the export as a command under our target. Instead we are going to export it right before.

1 2 3 dev : export HUGO_NUM =${ RAND_NUM } dev : css - dev hugo server -v -w = false --renderToDisk = true --ignoreCache

Here is the full Makefile. The RAND_NUM make variable is used in the sassc command to customize the name of the output CSS.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 THEME_PATH = ${ CURDIR } /themes/mytheme/ RAND_NUM = $( shell awk -v min = 1000000000 -v max = 9999999999 'BEGIN{srand(); print int(min+rand()*(max-min+1))}' ) dev : export HUGO_NUM =${ RAND_NUM } dev : css - dev hugo server -v -w = false --renderToDisk = true --ignoreCache css-dev : clean - css @echo "Processing CSS..." @sassc -m -l -t compressed ${ THEME_PATH } assets/css/core.scss ${ THEME_PATH } static/css/core- ${ RAND_NUM } .css @sassc -m -l -t compressed ${ THEME_PATH } assets/css/homepage.scss ${ THEME_PATH } static/css/homepage- ${ RAND_NUM } .css clean-css : @rm -f ${ THEME_PATH } static/css/*

Hugo Template

Now that we have our random number in an environmental variable in our build environment we can use getenv in a Hugo template. Here you see we are using the number as part of the CSS file’s name. The name will point to the CSS file created by sassc in the above Makefile.

1 < link rel = "stylesheet" href = "/css/homepage-{{ getenv " HUGO_NUM " } } . css " > < script > < / script >

Cache busting

Now we have a new unique random number on each build that we can use to create filenames for CSS and other assets. This is a brute force way of busting cache. It works, but has some drawbacks. Returning visitors will download all CSS assets, as it changes all their names, regardless if they have been updated or not.