Cache Busting CSS (and stuff) in Hugo
A how-to guide on how to get that CSS to reload on change
As it was with other bits and bobs in Hugo, getting the CSS to reload in browser was harder than it was. Yeah, no. It is easy, I just managed to underthink it. This process will work for other static content as well, like JavaScript.
And there it was, in the previous paragraph. The crux of the issue. I had put my css in the theme’s static/ folder; static/css/theme.css. No fancy SCSS; it was copied to my site — it just worked. Until I updated it, and it didn’t.
It didn’t, because my browser (Chrome) had cached my css from the previous visit, and was sure I hadn’t changed it. It was still called the same thing. Let me lead you through the mistakes I managed to make for this simple fix.
Fingerprinting the file
To bust out of the cache, we need to tell the browser that the file has changed. And there are different ways to do this, some more sophisticated than others. One effective and simple way is to change the filename every time it has changed. You probably know this technique; it is the simplest version control-ish thing ever. Filenames like Master_Thesis_2020_05_11_Final_2_New.docx
… yeah.
This sounds like a lot of work, and it is - if done manually. We can do this automatically when building the site. Instead of linking the elements directly, we can get them as a resource inside the <head>
tag, probably in your theme’s layouts/partials/head.html
file:
{{ $styles := resources.Get "/css/theme.css" | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}" integrity="{{ $styles.Data.Integrity }}">
This gets your CSS as a resource, computes a fingerprint and renames the file that will be on the server. A fingerprint is a short bit that is based on the contents of the file, and will change if the file is changed.
The bit in the integrity
attribute is there to tell the browser what the css looked like (what that hash was) when generated, to let the browser know if anyone tampered with it between the server and the reader. Probably more useful for scripts.
Stuff I got wrong
- When doing this simple bit, was that I had my CSS in the static/ folder. In order to Get resources, they must be in the assets/ folder. Bam. Fixed.
- (see below) When I first tried, I had the href link pointing to
$styles.Permalink
. This pointed tohttp://site.url/css/theme.b1ab1ab1a.css
instead of the https version. No idea why; but changing to.RelPermalink
fixed it.If you know, I’d love if you told me. Possibly with a link to a description added; yours or other. - I.. I found why I had to put a relative link. It was because I managed to put http in my baseURL — which made all resources load from http. And that failed. But the rest of the site redirected automatically to https. So that.