My Blog, in Hugo


Why not kick things off with talking about Hugo, the static site generation tool?! I’ve heard lots of good things about Hugo for some time now, and I definitely have a preference for tools written in Golang (personal bias). It’s fast, easy to pick up, and create a quick web site in minutes. Well… that’s an overstatement, I’m currently re-building this site in 4 ms each time I hit save.

Getting Started

My goal was to create a personal tech blog where I can share some personal projects I’m working on really put it down for my own use. Great if others can use it, and maybe I can just link to it occasionally from work or at a Meetup or something.

I wanted to run my blog inexpensively, so a static site tool made the most sense because I can deploy it and run no servers (plenty of that to do during my day job). I had an intern a while back show me how he made his site using GitHub Pages, which seems like a reasonable enough place to start. Git is an everyday tool for me, someone else is hosting, and I don’t even have to sync up to S3!

Rather than re-hash the getting started guide, the high-level steps for what I did are:

  1. Register domain, point CNAME to github pages.
  2. Set-up the GitHub pages repo, establish CNAME file per docs.
  3. Install the hugo cli (in my case I’m using Ubuntu 20.04 in the WSL2)
  4. Make a git repo for the GitHub pages
  5. Make another github repo for Hugo assets (draft static content, etc.)

Why two git repos? Well, I can now keep the work in progress in a private repo and use the publish workflow to deliberatlely publish just the static site content and nothing more.

Themes

Browsing through a library of themes is usually about as far as I got before actually making this blog. Understanding how to edit the config.toml to make all the cool features work, getting things to appear correctly, making my own sections and static content pages, and getting things like code blocks to look right can always be fun. Fun… right?

Well I’ve tried a few now and have just settled on the beautifulhugo theme for Hugo. It’s got a clean design, good configuration capabilities, example site structure made sense for me, an excellent place to start. The code fences are a little more “outlined” that I’d like, so indented blocks will have to do for today.

The practice of using git submodules to install a theme is a practical use of this git feature. I think submodules sometimes get a bad name when they don’t quite deserve it. With strong automation, the hard parts like remembering to init/update are just part of the process, and updates should now be trivial. Of course if this repo is ever moved or re-written, that’ll be less fun. I’ll put that in the “not very likely to happen” category for today.

Previewing

Feedback loop and fast feedback are super important in my day job… so why not make my personal blog fast, too! With Hugo, this one liner is all I really needed to achieve that goal:

hugo server -D

Start the process, click the link, hit save in VSCode and voila, the browser window is updating as well. Looks like caching is working, my site build times are now down to 3ms. My curiosity gets the best of me and I see a magic bit of javascript that is listening for site updates in order to power the reload in browser without even having to Cmd-r or F5. Feedback loop win for sure.

Now that I intend to write about it I can no longer reproduce, but when working with the theme’s config.toml, I was originally running into an issue that if a page compiled once it lived in cache, and even a Shift-F5 refresh wasn’t clearing it if I moved the content (to what should be a 404). It took actually restarting the hugo server to lose all of the cache. I’ll publish an update if I make it happen again.

Publishing

The return of git submodules! This is an even better use case for using them, too. No need to vendor all of my content back in my public directory here, just use git semantics to publish from that folder and watch it come to life. Since I own both repos, I’ll make a promise to myself not to tear it down without permission.

Tying it all Together

I’m a big fan of using taskfiles to automate simple user processes. The YAML syntax is friendly to use, and since we spend all our time in Kubernetes manifests anyways, it felt natural.

So far the main operations I need to do are a new blog page, starting the local preview server, publishing, and keeping my theme up-to-date, so I came up with something like this to help:

version: '3'

tasks:
local:
    cmds:
    - hugo server -D
    silent: true

preview:
    cmds:
    - task: local

publish:
    cmds:
    - task: clean-publish-dir
    - bash deploy.sh

clean-publish-dir:
    dir: public
    cmds:
    - git clean -df

update-theme:
    dir: themes/beautifulhugo
    cmds:
    - git submodule foreach git pull origin

new-blog:
    cmds:
    - |
        echo "New blog filename:"
        read BLOG_NAME;
        hugo new blog/${BLOG_NAME}.md;

Fantastic - now when I take a break for a few weeks, I’ll have a nice reminder of how to do the basics without having to re-visit the docs.

One small surprise

Rather than add to the taskfile, I noticed Hugo had a command for cleaning the public directory. That would be nice, since I had gone and execute the hugo command a few times, I had several untracked files living in the public directory that I did not want to publish. So I ran:

hugo --cleanDestinationDir

And it did exactly what it was supposed to, including deleting the .git directory and CNAME for my static site. Looks like I broke my publishing! Today I learned this is probably meant for when you deploy to something like an S3, so to make it play nicer with git, this will do:

git clean -df

This will restore the working directory of my git submodule back to the same state, cleaning all files including untracked files. The recursion and force is fine since all published content should already be commited to the upstream.