Skip Navigation

I, too, Wrote Myself a Static Site Generator

Published: 2022-02-18


You can view the source code here.


My history of playing with static site generator starts with Jekyll, Pelican, Hugo, Middleman, and eventually landed on Zola, which is my personal favourite among these off-the-shelf static site generators.1 There were very little things to complain about Zola, but one major painpoint was that - it isn’t built on Clojure (or any Lisp) so I didn’t know how to hack the sourcecode if there were something I want to change nor could I really understand the code. After reading Dominic’s I wrote myself a static site generator and Kenton’s Build Your Own Static Site Generator, I was really inspired and decided to follow suit.

It took several tries to get to my ideal level of complexity. Initially I was really annoyed by how imparative the main function was, and so I rewrote the logic into a desciptive build-plan, a series of descriptive steps each with a :build/op keyword, such as :ensure-folder, :copy-dir, or :page. My main function becomes a doseq on the build-plan that will dispatch on the :build/op key.2 This indirection of imparativeness is pleasing to look at but it’s really difficult to fit into my workflow. After a detour into the Common Lisp world with my other gamedev project, I decided to scratch that implementation and imbrace the imparativeness nature of the code. At this time, I also introduced the site-map.edn file, which is inspired by the flexibility of how Common Lisp assembles a package. I think I just prefer configuration over convention. I decided not to impose any significant meaning to the file structure to the markdown files under the contents folder. Instead, I explicitly link the source file to a target URI in this site-map.edn file.

Building atom feeds (RSS feeds) was also a bit challenging because this is the one thing I really didn’t want to break backward compatibility. (I’m really sorry if I still break your RSS client feed. I tried hard not to.) A really useful resource is W3G’s Feed Validation Service. One thing I found weird was that the would compile the Hiccup form [:feed {"xmlns" ""} ...] into <feed xmlns:b="" .... Notice that the xmlns attribute turned into xmlns:b here and thus invalidate the feed. For now I just YOLO’d it with a str/replace-first function.3 🤷 (Also, did I mention that I use python3 -m http.server to serve the site locally?)


With Dominic’s script, I was able to deploy my site on Netlify 🎉

As the time of writing, my code count is around:


  1. Zola has a relatively simple templating structure, and it’s very fast.

  2. This was highly inspired by the ClojureScript compiler code I read earlier that year.


This work is licensed under a Creative Commons Attribution 4.0 International License.