Hugo Minification

Since moving my site to hugo, I have only a handful of things left on my todo list. Once of them was bundling and minifying the files I serve so that I can properly push them with HTTP/2 push, and so that on HTTP/1.1 clients the site is as snappy as it can be (there’s also some argument to be made that bundling the files is an anti-pattern with HTTP/2, but I haven’t actually verified the data either way). None of this is really required, as my site is fairly lightweight by modern standards (though one day I’d very much like to work out if there’s any parts of bootstrap I can live without as my CSS bundle is still about 110KB which seems ludicrous to someone who was an active internet user in the 90s).

So Hugo Pipes looks the go, and while the documentation is fairly terse it doesn’t seem all that difficult. I threw together all the things I wanted, gave it a shot and… it didn’t work. It seems resources.Get only looks in the “assets” directory, my “assets” are in “static” (a leftover from the theme I borrowed as a starting point to write mine), so it couldn’t find them. Shift those over, and it works! The final template code:

		{{- $bootstrapCss := resources.Get "css/bootstrap.min.css" }}
		{{- $bootstrapFontAwesomeCss := resources.Get "css/font-awesome.min.css" }}
		{{- $bootstrapOverrideCss := resources.Get "css/override.css" }}
		{{- $css := slice $bootstrapCss $bootstrapFontAwesomeCss $bootstrapOverrideCss | resources.Concat "css/darkstrap.css" | resources.Minify | resources.Fingerprint "sha384" }}
		<link rel="stylesheet" href="{{ $css.Permalink }}" integrity="{{ $css.Data.Integrity }}" />

The resulting output:

		<link rel="stylesheet" href="http://localhost:1313/css/darkstrap.min.6c443406845f5793e7d2b714bc008d5d923d826cc07b7f5e62ff611057e3a84e8bbafe987dded7309d7db365986d66f1.css" integrity="sha384-bEQ0BoRfV5Pn0rcUvACNXZI9gmzAe39eYv9hEFfjqE6Luv6Yfd7XMJ19s2WYbWbx" />

The only trouble with this is that goddamn cache-buster in the file path. That’s probably desirable for some folks, however I make almost zero changes to my theme pretty well ever… I’m much more likely to throw the entire thing away and start anew than I am to make any sort of breaking change to the file. Importantly, as I hand-write the URLs to HTTP/2 push in my server configuration, I need the files to be in a predictable location. If I do make any changes to the file, I’ll blow away my CDN cache and it probably doesn’t matter if the file stays cached on the user’s browser for a while afterwards (though I’m not sure if SRI will affect that?)… I’m in the unique position where I need the ability to instantly invalidate the caches much less than I want that sweet sweet bragging rights on PageSpeed.

After digging in to the source for resources.Concat I couldn’t work out where on earth this random string was coming from. It then occurred to me that it’s not changing each time I rebuild the site, and that maybe it’s a hash?

echo 'bEQ0BoRfV5Pn0rcUvACNXZI9gmzAe39eYv9hEFfjqE6Luv6Yfd7XMJ19s2WYbWbx' | base64 -D | hexdump
0000000 6c 44 34 06 84 5f 57 93 e7 d2 b7 14 bc 00 8d 5d
0000010 92 3d 82 6c c0 7b 7f 5e 62 ff 61 10 57 e3 a8 4e
0000020 8b ba fe 98 7d de d7 30 9d 7d b3 65 98 6d 66 f1
0000030

Yep, it’s a hash, so it seems likely that resources.Fingerprint is responsible for it instead. Removing it reveals that yes, that’s the case. Do I care about SRI? I’m not sure, it’d be a nice to have, assuming it doesn’t mess with caching (ideally, if the user requests a new page, and they have my bundle cached, but the SRI hash doesn’t match, they should re-download it… but I’m not sure if that’s actually what happens?). I can easily remove it for now, but in case I want to add it back later on, it seems easy enough to fingerprint a copy of the resource:

		{{- $bootstrapCss := resources.Get "css/bootstrap.min.css" }}
		{{- $bootstrapFontAwesomeCss := resources.Get "css/font-awesome.min.css" }}
		{{- $bootstrapOverrideCss := resources.Get "css/override.css" }}
		{{- $css := slice $bootstrapCss $bootstrapFontAwesomeCss $bootstrapOverrideCss | resources.Concat "css/darkstrap.css" | resources.Minify }}
		{{- $cssSRI := $css | resources.Fingerprint "sha384" }}
		<link rel="stylesheet" href="{{ $css.Permalink }}" integrity="{{ $cssSRI.Data.Integrity }}" />

This gives me what I want: a predictable resource URL, but with the SRI calculated and Hugo handling everything for me.

That’s got me down to two minor annoyances on my todo list, however in a passing thought I might add a third one: pull the rsync results from the upload process, and fire off CDN cache purge requests for those automatically. Not sure I care about that one either?

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry

Duncan Home From Camp

Duncan was away at camp this week - three days at Roses Gap with his school. Dropping him off was an indication of how things were going to go: noisy, I felt quite sorry for the teachers going along. The weather here was fairly inclement, but apparently it must’ve been better there as they got to do lots of the activities that we thought for sure would be canceled.

On Friday afternoon, we had to pick him up around 3pm, so I managed to sneak away from work early to go with Sabriena. Not long before-hand we got a call from the father of one of Duncan’s friends - he’d managed to run out of fuel and couldn’t do anything until his partner got home, and could we pick his Son up too? Sure, I mean we’re out anyway!

Dropped his friend off to a very apologetic father, then back to work to finish up what I was doing. After that, we started hitting the Minecraft pretty hard and that’s basically how we spent the rest of the weekend.

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry Newer Entry

CSP header woes: generating hashes for scripts

After pushing Hugo version of my site live, I expected a handful of issues mostly surrounding URLs changing (ditching the .html extension). I’d completely forgot about my security settings, and came upon a lovely CSP warning immediately after:

Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).

Awesome, at least I know what that one is - I include hashes of the inline script (just a short stub that fires timeago.js), and when I switched my theme around I changed the whitespace, which will have invalidated the hash I bundle in. Problem is, I generated these headers so fucking long ago, and if I did document how it was done I sure didn’t put them in a place that’s easy to find.

So it turns out generating them isn’t super hard. Here’s the offending script:


		    <!--
		    jQuery(document).ready(function() {
		        jQuery("time.timeago").timeago();
		    });
		    -->

It’s (probably) important that there’s a newline at the start, and then some tabs and no newline at the end - not sure if either of those things will come through on my site’s formatting though.

So I just copy+paste that, verbatim (as in, exactly what’s between the opening and closing script tags, whitespace and all) into a text file, and per SRI hash instructions, generate the hash like so (I’ve slightly modified the one-liner:)

echo -n 'sha384-'; (openssl dgst -sha384 -binary /path/to/script.js | openssl base64 -A); echo

The resulting has is stuffed into the CSP header:

script-src 'self' 'sha384-XC2Oe5F/T4ZBZrVZ/lb529X77T7ZPuJtaH+i+uz3+GVRCQCqPEMT7UFDsCNwm0JD'

I also put it into the integrity attribute of the script tag, though I’m not actually sure if that’s required (I can’t see how it would help, but it was like that the first time I did it so I’ve left it).

After flushing the cache on my site, the tiny bit of jQuery I use is working again.

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry Newer Entry

Hello Hugo!

I first learned about Hugo quite some time ago, and there’s a lot to like. I quite like (even though I suck at it) the Go language, and I’ve been looking for an excuse to hack on it some more. It’s very fast, and has some built in features I’d been meaning to write scripts for Pelican to do (like creating new posts automatically). Plus there’s the whole live preview thing, which looked pretty neat.

Pelican, I absolutely adore, but it’s so very slow. If I make one tiny change, my 12-cores of X5650 Xeons take approximately 15 seconds to regenerate all 600-something blog posts into a static site. In contrast, Hugo does it in about 400ms, but the live-reload thing makes it even nicer… if you have the local site open in a browser on one screen, and save in your editor on the other, your changes are already there for you. That makes it super-nice to blog on!

So anyway, one of my co-workers mentioned using it for a site and I decided to have another crack at it after work on Friday, as one does.

I wrote a short script to convert my Pelican markdown to the YAML-based frontmatter that Hugo wants. It’s pretty nasty and super-specific to my site, but it works.

I had to change several things around, such as creating a handful of _index.md files, and fixing one or two timestamps that weren’t in the formats my script handles (Pelican is apparently not terribly picky!). By far the absolute longest part was porting the theme across - I thought I could save some time by starting with a minimalist Bootstrap theme, but I’m honestly not sure it saved anything as it’s laid out completely different to mine in both HTML and how I wanted it.

However after about three hours of tinkering (with a break for dinner in the middle, so around 5 hours total), I’ve got it almost complete. There’s a handful of things I still need to fix - chief among them the internal links which all link to .html files, and I may just rip the bandaid off and remove the extensions like I should have done some four years ago when I ditched blogger.

After that it’s mainly just cleaning up the theme files, and shifting the GitHub repo that drives my site across, and working out how to push it up to the server that hosts the live version. Comparatively speaking, that stuff is the easy part. Here’s a list of the stuff that I know is still broken:

  • MathJax - I think I can fix this fairly easily though.
  • Minifying JS/CSS - “Hugo Pipes” looks the ticket for solving this.
  • Next/previous links - what Pelican calls “Neighbours” and I accomplished with a plugin, not 100% sure how to do it with Hugo. Dead simple with .NextInSection and .PrevInSection.
  • Yearly/monthly indexes - this seems to be an ongoing problem that a few folks coming across from WP/Blogger complain about. Not 100% sure I give a shit, to be honest.

Edit 2019-11-03: I’ve decided that I’ll just leave the .html off the URLs, and put some 301 redirects on my webserver to handle stripping them off.

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry Newer Entry

ZFS: changing device IDs.

When I created my zpool on FreeBSD, I went to great lengths to use volume names that matched the serial numbers on the disks. I then made sure the last 7 digits of the serial numbers were visible while the disks were in-situ, so that if one failed I could immediately tell which. This all went out the damn window when I moved the pool to Linux, because ZFS-on-Linux imported them as standard Linux disks (/dev/sd[bcd]).

That’s a pain in the arse, because the ZFS disks are in the higher numbered drive slots, so if I add or remove an extra disk and reboot the machine, Linux re-letters them, and ZFS needs help to figure it out as it seems to give up if nothing matches what’s in the cache file. The cache file, by the way, is binary in part, so editing it by hand didn’t seem like much fun. This is all not to mention that my original intention of knowing exactly which disk to pull was still not working.

For work today, we ran into a situation where we had unusually named disks on one machine, and I figured I’d test it at home, scratching my itch at the same time.

So I recorded the procedure necessary to do it.

Horsham, VIC, Australia fwaggle

Published:


Modified:


Filed under:


Location:

Horsham, VIC, Australia

Navigation: Older Entry Newer Entry