Getting to Know Hugo

Sometimes it’s tough as a web developer to avoid getting paranoid about your personal website. That design you did a year-and-a-half ago? Looks stale! That quick little php script you wrote to dynamically generate a list view from a directory? Feels hacky!

I’ve been feeling that anxiety build up again lately, and this go around, I decided to see if I could save me from myself by using something slightly more out-of-the-box, but also lightweight enough that I had plenty of freedom whenever I wanted to roll my own custom bits. What I settled on was a static site generator, Hugo, and I decided to make some notes here about my journey in

Why a static site generator?

Static site generators are all the rage these days. Why? If you want an in-depth answer to that, look here, but if you’re ok with the short answer, then read on!

  1. They’re fast.
  2. They’re easy to get up and running.
  3. They’re safer than using a database-driven CMS.
  4. They’re designed to let you make updates with a text editor rather than a GUI.

If that sounds perfect to you, then you’re definitely in the right state of mind to give a static site generator like Hugo a try, but you should also know that they’re not suited to everyone’s needs. If you have a multi-user blog, require dynamically updated content, or have authors who aren’t comfortable without a visual UI, then something like Hugo probably isn’t right for your needs–you need a robust database-driven CMS like WordPress or Drupal. But if you mostly want a few custom pages and a blog that’s served quickly and easy to keep up to date using the code repository and hosting platform of your choice, then Hugo’s a solid choice.

Why Hugo?

There are a fair number of choices out there right now for static generators. Jekyll, Middleman, Metalsmith, and Hugo are just a few. So why Hugo?

I can’t speak to all the static generator choices out there, but having used Jekyll before, the reason I chose Hugo for my personal site was largely for ease of set-up. Jekyll is fine if you’re using a Mac which has Ruby built-in, or if you’re already pretty comfortable with a Ruby workflow, but if you’re not or you want the ability to easily get into static site generators while working from your OS of choice, Hugo’s a clear winner in this department. Even as someone familiar enough with Ruby to work in Jekyll without too much difficulty, I still never had any regrets deciding to use Hugo and I saved myself some set-up time. Win!

Other good reasons for Hugo: it’s fast, nicely documented, and if you like learning new things, gives you and excuse to learn a bit about the Go language (although if that’s not your thing, you still shouldn’t find the templating too difficult).

Easy to setup, less easy to configure

Hugo has some pretty great documentation, and the Quickstart Guide can get you up an running in no time. Really, go give it a look! I can’t explain the basics of Hugo any better than they already have.

Where I ran into the most challenges wasn’t in getting started or creating content, it was in figuring out the best ways to make and modify themes. As someone who spent a few years doing Drupal and Wordpress theming, I was a little surprised to find this seemed to be a bit of rough spot with Hugo. But Hugo’s still a work-in-progress, so undoubtedly things will change here. And I’m sure my strategy will change, too, as I get to know Hugo even better.

Because Hugo doesn’t come with a default theme or have a minimalist starter, it’s a little tricky to sort out best practices from developer idiosyncracies when browsing themes. But the essence of a Hugo theme is the partial. Partials are simply little re-usable chunks of code that create the various sections of your site. You then use those partials almost like Lego bricks, snapping them together in whatever arrangement you like to make your website. A well-built index.html page in Hugo might look something like this:

{{ partial "head.html"  . }} 

{{ partial "header.html"  . }} 
{{ partial "about.html"   . }}
{{ partial "work.html"    . }}
{{ partial "posts.html"   . }}

{{ partial "footer.html"  . }}

That’s right, there’s no HTML at all in this index.html. It’s all partials!

In general, this is a pretty handy way to build a static site, but there are still some gotchas to trying put all your Lego bricks– er, I mean, partials, together. One temporary roadblock I encountered was when I needed one of my partials to have slightly different behavior depending on what page it appeared in.

The theme I decided to fork was built primarily as a single-page website, which was great for my homepage, but I wanted to have some posts, too. Hugo of course gives you the flexibility to do this, but there was a problem with my navigation menu partial. On the home page, the links should be anchors so that the page simply scrolls to the correct location. But if my posts were going to appear as their own separate pages of the website, then my navigation menu items would need to be proper links. I needed to use conditionals of some sort to make this work. As long as I could identify the index.html page versus any other page of my site, I could still use one partial for my navigation, but specify the different behaviors I wanted. So what was the problem?

The ability of Hugo to detect the home page is an undocumented feature.

Oh :-(

Fortunately, there is a feature in Hugo to let you do this, which I found by searching around the forums. As of Hugo 0.15, the IsHome variable was added to let you detect the homepage, so you can do something like this:

{{ if .IsHome }}foo{{ else }}bar{{ end }}

Once I found that out, it was pretty straightforward to make my navigation partial do what I needed, but it is one of the current weaknesses of Hugo that sometimes the features that might seem really obvious to have to you as you build out your site may only exist in a shadowy, limbo-world way in these early stages of Hugo.

Hugo also lets you different types of content for your site and lets you define fields and use page templates that are specific to your content types. For example, you might have blog posts that will have very different data and layout needs than, say a product or project page. Instead of having to customize these different types of page or partial by hand, you can use Hugo’s archetypes to give unique structure to different types of content.

The advantage of archetypes is that you can create custom data fields that can be used in your templates, which is just one of the features that makes Hugo a really great choice for buidling out fairly large and complex static sites. The disadvantage of the archetyping system, however, is that it is often unclear how to actually access those custom params and how to debug them when they’re not working.

One such situation I encountered was when I created a partial with this code to try and access a custom field I had created called displayImage:

{{if isset .Params "image" }}
	<img src="./project/{{.Title}}/img/{{ index .Params "displayImage"  }}"/>

This didn’t work. Why? Apparently, case sensitivity gets lost in stange ways. Even though the param I defined in my YAML was displayImage I had to use .Params "displayimage" to access this variable. Anything other than all lowercase would fail.

Now, as a newbie to the Go language and Go templates, maybe this is just something a Go person would know. But it certainly took a chunk of my time trying to figuring out what was going wrong here. Which is why I say that while Hugo has a lot of strengths to it, you still need to be prepared to venture out into terra incognita when you build your first Hugo site.

One final drawback to working with Hugo in it’s current state is the somewhat incomplete documentation on best practices for creating child themes. As I mentioned above, Hugo doesn’t come with a default theme, so if you want to do any custom theming at all, it’s still easiest to start with a pre-created Hugo theme and then add your own customizations on to that, a common practice in the CMS world. Ideally, you want your customizations to be an extension of the base, or parent theme, so that you can update that them without breaking your custom child theme.

In the Hugo docs, partials are described as the key to making modifications to themes while still maintaining the parent theme’s future compatibility. However, how this relationship is supposed to work remained unclear. Unfortunatley for me, this means that the changes I made to the artists theme for this site will probably not allow me to directly upgrade the theme in the future. For me, that’s not likely to be a problem since I’ll likely want to re-design my site before the theme gets too out-of-date. But if I were trying to do a professional project with Hugo, I would definitely need to resolve the uncertainty around the proper creation of child themes. Forking the parent just wouldn’t be a viable option.

No going back

Although I still have a lot to learn about working with Hugo and Go more generally, I still loved the experience of re-building this site on the Hugo stack. Unless you’re learning HTML for the first time, building a personal site should be about your content, not about figuring out how you’ll include the header on every page (Server-Side Includes, anyone?) or how to scrape your content from a directory without using a proper CMS. Hugo was everything I wanted and needed it to be, and look forward to exploring it further, and hopefully even introducing clients to it someday. Why saddle a small business with a hard-to-secure WordPress site if you can get them building pages with Hugo? Welcome to the future, my friends!

see more posts