Rewriting My Personal Site with Hugo

Mar. 4, 2019 • 4 mins

A couple months ago I created my personal website called andrewdavis.me. I built it as a custom server side app in Go with MySQL holding the content. I wrote about the experience in Building My Personal Site with Go and TailwindCSS. I enjoyed the project, however, I recently wanted to make some SEO improvements and decided maintaining a custom app was more work than I wanted. I started looking at different static site generators and found Hugo. It is a really fast site generator that uses Go templates for HTML and Markdown for content. Hugo is very flexible, but also easy to use so I was able to move my site to it in a single day! In fact, I open sourced the code so you can see it all here on GitHub. Now, my site is served from HTML files on GitHub Pages, making it much faster at rendering. Here are a few reasons for why I liked Hugo so much and why you may enjoy using it for your next project.

Easy to Install and Start a Project

Hugo is a simple binary that can be installed on any OS (I used Homebrew on MacOS brew install hugo). To start a new project, open a terminal and run hugo new site blog. Hugo will create a folder called blog and generate a project skeleton so you can start adding content. To start building templates, add a _default folder in the layouts directory. In there you can create a new file called baseof.html which will become the base template for all your pages. After that you can create an index.html, list.html and single.html template. The index template will be used for the homepage, the list template for any list pages and the single template for content pages.

Next, you can start adding Markdown in the content folder. You can create Markdown files like post.md or post/index.md which will create different paths: /post.html and /post/ respectively. Each markdown file must have frontmatter, but it can be written in YAML, TOML, or JSON. I wrote mine in TOML, which makes a page look like this:

+++
title = "My Blog Post"
date = "2019-03-01"
+++
The content of my blog post goes here.

To build the pages, you can run hugo server in your terminal and it will start a server for you to see the site at localhost:1313. The server will also automatically reload anytime you make changes to your content. Hugo takes the Markdown pages’ content and builds them into individual HTML pages using the Go templates. In the template, the Markdown file will be injected using predefined variables so you can use {{ .Title}} and {{ .Content }} to indicate where the Markdown data should appear in the template.

Of course, there is a lot more to templating and content, which you can find in the docs. Hugo is very configurable and can do as little or as much as you need.

Automatic Code Highlighting

On the previous iteration of my site, I used the Prism.js JavaScript library to enable code highlighting. It worked well, but all the styles are added client side, which is unnecessary work for the browser. Hugo uses a Go syntax highlighter called Chroma that will add the CSS to the HTML in the build process. To have it run on Markdown codeblocks, just add pygmentsCodefences = true in the config.toml in the root of your project. The config.toml file is the main configuration file used by Hugo when building the site.

Integrated CSS Processing

I like to use PostCSS for my stylesheets and Hugo works with it easily. I just created a package.json with postcss-cli installed and my PostCSS plugins. Then, I created a postcss.config.js file (not required by Hugo, just what is necessary for PostCSS). Afterwards, I created a CSS file in the assets folder and then imported it into my baseof.html template using:

{{ $css := resources.Get "site.v01.css" }}
{{ $style := $css | resources.PostCSS }}

<link rel="stylesheet" type="text/css" href="{{ $style.Permalink }}">

Now, when I build with Hugo, it will automatically compile my stylesheet and link to it in my base template.

Easy Deployment

Hugo has multiple different ways to deploy a site. When you run hugo in the root of your project, it will build the files in a public folder. I just followed their guide for deploying to GitHub and created a publish.sh script that takes the contents of the public folder and commits it to a separate git branch. The deployment branch is then used by GitHub Pages to serve the files.

Conclusion

I really like that Hugo is straight forward and does not require writing JavaScript to build a static site, like many other generators. Plus, I can now easily update templates and add more features using frontmatter variables without having to write much code. Generated HTML files allow me to not maintain a server setup, decreasing the amount of maintenance time to keep my site going. All in all, I count it as a successful move and plan to use Hugo in the future!