What I wish I knew before writing my own static site generator
| 6 minute readIn creating the website you are hopefully reading this on now I decided to write my own static site generator rather than using something like Jekyll or Hugo. My main reasoning for this was I wanted to end up with something that felt uniquely mine and figured it would be easier to do it myself rather than understanding something like hugo's configuration at a deep enough level to make that happen.
Initially I figured I would do it with a Makefile and a couple of small python scripts for some templating and markdown compilation. In the end I still did use make and python, but like many software projects I may have underestimated things a tad.
Commonmark is good actually
One of the goals for my static site generator was to have as few dependencies as possible, as I want this site to be as easy for me to maintain going forward. If I come back to it after many months I absolutely don't want to be messing about with dependency upgrade hell.
One of the first decisions I had to make what which library to use for compiling markdown to html. After a very quick search I chose the most popular package just titled Markdown. While it did work fine I was not massively impressed with it's documentation and plugin system.
I was also aware that the commonmark spec existed and standardised the main syntax of markdown, meaning you could write something that was compatible with many different libraries. Markdown (the library) did not support commonmark and I thought it would be a good idea for the blog to use something that did so I could more easily swap out the library if needed. From a quick search it seems other people have had compatibility issues with my original choice as well.
Anyway in the end I chose markdown-it-py and this has served me well. Definitely a lesson that going with the biggest most popular library is not better for ease of maintenance than something that is standards compliant.
Frontmatter, we kind of need that
In my markdown files I use some frontmatter which looks something like this:
---
title: My very cool post
author: Jane Lane
published: 2025-11-06T17:10:00+11:00
---
This practice is basically stolen from other site generators as far as I can tell, but it isn't really standardised. Which means that your average markdown library doesn't actually know how to deal with it out of the box, but most seem to have plugins to handle it.
Initially I did use the plugin for Markdown, but it's API was a little weird and it didn't actually support proper yaml, having it's own simpler syntax instead.
So in the end I thought if I was going to use a basic syntax anyway I might as well write my
own. I ended up with a simple system that reads key value pairs separated with a : and optional
whitespace, then I just manually convert from string to other types when constructing my Meta type
which holds this metadata.
But the real advantage of all this was that I could have it completely separated from my choice of
markdown library, I just pass the file object to my frontmatter code which reads everything between
lines containing ---. Then pass the same file object to the markdown library to read the rest of
the file as markdown. This worked well when I later replaced the markdown library and didn't have to
touch the frontmatter code or mess about with plugins.
Custom fonts and subsetting
As part of the whole "making it feel like my own" thing. I knew I wanted at least one custom font and Jacquard 12 took my fancy while browsing Google Fonts one day.
I also got into the idea of font subsetting after reading the excellent blog You're loading fonts wrong. The idea being that if you are only using a small subset of characters in a font you are actually wasting bandwidth and making your site slower by loading the entire font instead of a subset with the characters you actually use.
In my case I was able to add an extra step into my Makefile that converted the full font into a web
font with just ascii characters and the bar character (|) that I am using as a separator.
With all of this I was able to move away from using Google Fonts to serve the webfont file (which I already wanted to do as I find it uncomfortable from a tracking point of view) and end up with a more performant site in the process.
Getting the damn thing to not look terrible on a phone
After setting up most of the site I was having this problem where everything looked great on my laptop but viewing it on a phone (which I where I read most blogs at this point) the text looked super small, almost unreadable. And I knew that with the CSS setup I had, it should be scaling up.
It took me way too long to realise that I needed to define a device width viewport which can be
done by just adding <meta name="viewport" content="width=device-width, initial-scale=1"> to the
<head> of the page. Without that a mobile device will actually render at a larger size and then
shrink it down to fit the device. This works ok on websites that aren't designed
for mobile, but is terrible otherwise and seems to mostly be a hangover for when the web was almost
entirely built for larger screens.
All this made me realise that something like a basic HTML document with all the sane defaults would be useful. But I didn't find anything like that in my brief search.
Accessible contrast is good and easy
Like most people probably do I spent a bunch of time messing with colour schemes and deciding on how I wanted everything to look. Which is fun and all, but it is surprisingly easy to end up with something that doesn't pass the accessibility standards for contrast (WCAG).
But this is actually a very easy thing to fix these days, it turns out pretty much all browsers now have a WCAG checker built in to the colour picker in dev tools. The one in Firefox gives you a little tick for AA or AAA when messing about with colours and makes it super easy to keep it green.
After a bit of fiddling with colours the result was easier on my eyes too.
RSS is a mess of a specification actually
One thing I knew I wanted on the site was an RSS feed. Seemed simple enough until I actually started having a look at the RSS specification over at the rssboard website.
If you are used to reading thorough specs from RFC's this is a bit of a step back. For a start the site has ads all over the place, then there is the very confusing versioning with the sidebar saying 2.0 is current, but there are also mentions of 2.0.11 and 2.0.1 in various places.
At least they do have an RSS validator on the site which would be great as something like a command line tool I could lint my output with instead of having to paste in a link once it's already public.
All this did make me appreciate the atom protocol a lot more, but I ended up sticking with RSS as I assume it has better compatibility and I had already dealt with the issues. May revisit that in future though.
Incremental compilation is hard
Using make has in general been positive, I can just write my python commands to process individual
files and have make deal with passing in dependant files and calling everything in the right order.
At the start this was very simple, but it did get a bit complex as things grew and I did run into some peculiarities, like that folders don't actually update their timestamps when files in them change! Which is just a standard unix behavior I had apparently not put much thought into before.
It also did get a bit tedious specifying all the dependencies at some point, because of course you have to deal with things like what should rebuild if the code of the static site generator changes. Then once I started using templates a bit more you need to make sure "base" templates used across the site also re-build all the posts.
Now that it's up and working though I feel like the maintenance will be small, but we will see.
The performance of all this is not amazing with a full re-build taking close to 3 seconds, maybe if I really get into SSG speed or my site grows a bunch I would re-think it.
Stopping the tinkering to actually write something!
As fun as tinkering with all this is I did end up doing that a bit too much instead of sitting down and actually writing a post. After all what use is a site with nothing of substance on it.
I did come across How to make a damn website while working on this, which makes that point really well and has great general advice too.
Conclusion
Anyway it has been a fun time, guess I should go back to writing the blog post I actually created this site to write, rather than getting distracted for several months and writing about the site itself. Oops