Building a barebones website/ theme pair with Hugo

When looking to build this website I knew I wanted 3 things, ease of setup/ maintenance, no JS, and simplicity. If you couldn’t already tell, I don’t love flashy sites. I’d much rather a fast loading, small, static site than some massive react esque thing that takes 10 minutes to render.

I landed on Hugo, it sounded fast, and there seemed to be a vast number of themes. However I quickly ran into an issue with finding a theme that fit my needs/ wants. This is a blog post on rectifying this. If all you care about is the code, it can all be found on my github. This is also very loosely based on the blog post hugo for fussy people by Jacqueline Nolis.

After picking Hugo, I started to go through themes, however they all either included features I really didn’t want, or were too basic. So I ended up deciding to start from scratch

Prereqs/ Starting with a blank theme

You will need your Hugo version to be >= v0.132.0, for the katex rendering support. We also need a starting point, you can get one by running the following.

1hugo new theme foo

This will generate the directory themes/foo, I then built my website ontop of the one provided (this might be bad?), but it is still useable as a theme. I also cleared out all the included JS, as I didn’t want any in my site. Now, I was ready to start building.

Setting up server side latex rendering via katex

As an aside, I find the entire concept of libraries like mathjax slightly baffling. The entire internet seems to be convinced that making every user of every website render each piece of latex every time they visit a page is a sane way of doing things, despite the rednered latex looking the same on all devices. Thankfully, there are tool like katex which allow for sensible server side rendering. Hugo recently added support for this feature in v0.132.0 To do this, I added the hook layouts/_default/_markup/render-passthrough.html, as follows.

1{{ if eq .Type "block" }}
2  {{ $opts := dict "displayMode" true }}
3  {{ transform.ToMath .Inner $opts }}
4{{ else if eq .Type "inline"}}
5  {{ transform.ToMath .Inner }}
6{{ end }}

This tells hugo, to convert the block/ inline latex respectively. We also need to provide some delimiters in the config file to use this in markdown, so in my hugo.toml I added.

 1[markup]
 2  [markup.goldmark]
 3    [markup.goldmark.extensions]
 4      [markup.goldmark.extensions.passthrough]
 5        enable = true
 6        [markup.goldmark.extensions.passthrough.delimiters]
 7          block = [['\[', '\]'], ['$$', '$$']]
 8          inline = [['\(', '\)']]
 9  [markup.goldmark.parser]
10      [markup.goldmark.parser.attribute]
11        block = true

This allows us to use the \( \) delimiters for inline latex, and $$ $$, \[ \] for block latex. Finally, I added the katex css file to layouts/partials/head.html, this is required for server side rendered katex to display properly.

1<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css" integrity="sha384-nB0miv6/jRmo5UMMR1wu3Gz6NLsoTkbqJghGIsx//Rlm+ZU03BU6SQNC66uf4l5+" crossorigin="anonymous">

The following is an example of using the delimiters in your markdown vs how its rendered.

1inline math: 
2\(\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}\)
3
4block math:
5\[\lim_{x\to 0}\frac{\sin(x)}{\x} = 1\]

is rendered as

inline math : ex2dx=π\int_{-\infty}^{\infty}e^{-x^2} dx = \sqrt{\pi}

limx0sin(x)x=1\lim_{x\to 0}\frac{\sin(x)}{x} = 1

Note that if you refresh the page, there isn’t the lag where you can see the raw latex that comes with rendering on the fly. Now that we have latex support setup we’re half the way to being done (this was the only “frill” I wanted my site to have). Now we can work on themeing the site.

Customise your css/ layouts

Now you just have free reign over what you want on your site & where, I only wanted 3 main sections, about, blogs, and a link to my github. So I just put them into the layouts/_default folder, and specified their layout in the relevant md file with layout = 'about' in the header.

For css, I ripped the basic theme for pelican, and made my own modifications for things like code blocks. I also pulled the Cousine font from google fonts, as I just wanted a simple monospaced font.

All in all, this is definitely not using the many powerful features of Hugo, however it does give me a website that I can clone anywhere and build with no dependencies other than Hugo. It took me a bit to figure out integrating the katex, so I thought I would write all this up here as the first blog post I wrote for this site.