Hugo: Improved static asset cache busting

hugo improved asset cache busting
Image courtesy of Zyada

Previously I was using a quick fix solution to bust cache on my static css files. Briefly, cache busting is a strategy of uniquely naming CSS and Javascript assets to improve page loads, and speed up propagation of changes when updates to the layout are made. More on cache busting.

My previous technique worked as needed but suffered from a couple limitation. I was using random numbers appended to the CSS filename to get a unique filename. However the random number was updated for every CSS file for every change. This means that one small update would force the client to download a ton of CSS that it did not need. The random number was also really fickle. Making updates and reverts always resulted in new file names. This could have been mitigated with a Unix Timestamp, which would allow rolled back files to use the old file name. This is a little nicer, but still a bit ridged.

I decided to move to a process of using the git SHA1 hash of the Sass file as the unique identifier for the filename. Using the git commit hash has many benefits over a random number, or a Unix timestamp. Each file would have it’s own unique hash identifier, and the hash is only updated for each file if that file had been updated. This means unchanged files will still be cached by the browser using, reducing the number of HTTP requests needed to lead a page after an update. The git hash is specific to the Sass file at a specific state. If the file ever needs to be reverted the hash will be the same as the original state. This means reverted files will still be cached by the client on previous visits.

The second major change was to put the unique file names into a JSON data file instead of an environmental variable. Hugo can read environmental variables to get compile time data into Hugo. While it is useful it has a smell to it for my use. I have a large number of CSS files and it started to become cumbersome. I also never enjoyed the idea of polluting the global variable space, even if it was ephemeral in my build step. Using the JSON data feels like the proper place for this.

This script takes an input directory with Sass files and an output directory where it will put the CSS files.

This script reads Sass files and generates CSS files with the commit hash in the file’s name. Then generates a JSON data file mapping the file to the filename.

Here is an example of the data file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
    "blog-archive": "blog-archive-f1a20c8.css",
    "blog-article": "blog-article-265ac9b.css",
    "blog-home": "blog-home-7f2771e.css",
    "blog-social": "blog-social-265ac9b.css",
    "core": "core-265ac9b.css",
    "core-vars": "core-vars-265ac9b.css",
    "homepage": "homepage-ef2f43d.css",
    "resume": "resume-f1a20c8.css",
    "site-footer": "site-footer-265ac9b.css",
    "site-header": "site-header-bafd301.css"
}

In the Hugo template file you would get the unique filename, with the hash, by using the base filename as a key.

1
2
<link href="{{ .Site.BaseURL }}css/{{ index .Site.Data.snowblind.css "core" }}" rel="stylesheet">
<link href="{{ .Site.BaseURL }}css/{{ index .Site.Data.snowblind.css "site-header" }}" rel="stylesheet">
Hugo: Improved static asset cache busting by
  hugo  tools  css 
Like what you read? Share it:
  Facebook   Email