Make a static website

Building a static website with pandoc and Make

I’m a believer in simple static html based websites, but I’m not quite so dyed-in-the-wool that I want to write html by hand. That being said, my homepage is built by hand in raw html, and edits I do are directly on the html.

That isn’t very scalable, and I’ve recently started this blog. In other projects, especially for the TinkerSoc website, I’ve used static website generator tools. First, we used Jekyll, a Ruby tool for turning markup into a whole website. It’s scriptable, extensible, generally quite good. It’s even supported by github pages! You can add a repo containing a jekyll website, and prod GitHub in the right way and they’ll build it for you and host it at Unfortunately, if you use GitHub’s build, you can do quite a lot less with Ruby to extend it.

With poor performance, and weak github integration we eventually rebuilt the website using Hugo, a Go based static website generator built with the same aims - but it’s really fast.

All of these tools are pretty heavyweight though, and have significant learning curves. I’ve done the hard work, I could use them for my website, but that would be procrastinating a little too much. So what am I doing instead? Well, just Pandoc and Makefiles.

Building articles

First up: how do I build an individual post? Well, that’s easy, I can call pandoc on a .md file and fill in a template.

TEMPLATE = ./blog-template.html
PANDOC_FLAGS = --standalone --highlight-style kate --template=$(TEMPLATE) --mathjax

%.html: $(TEMPLATE)
    pandoc $(PANDOC_FLAGS) -o $@ $< 

Each article needs a front-matter block with the date, title, subtitle, and a published state:

title: Make a static website
subtitle: Building a static website with pandoc and Make
date: 2022-11-01
published: true

I'm a believer in simple static html based websites, but I'm not quite so dyed-in-the-wool that I want to write html by hand.


Okay, the template. Most of this is boilerplate that I’ve pulled from my home page. There are a few $macro$s which pandoc expands:

<!DOCTYPE html>
<html lang="en">
  <title>$title$ &mdash; Simon Cooksey Blog</title>
  <meta name="viewport" content="width=device-width, user-scalable=yes">
  <link rel="stylesheet" href="">
  <link rel="stylesheet" type="text/css" href=""/>
  <meta name="description" content="Personal webpage of Simon Cooksey, summarising academic research projects and funding.">
  <meta charset="utf-8">
    <h1 class="title">$title$</h1>
    <div class="byline">$subtitle$</div>
    <div class="date">$date$</div>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
            <li><a href="/photography/">Photography</a></li>

Building an index page

This is where Hugo and Jekyll excel, and pandoc is less useful. Thankfully, I want a very simple index page, so a little bit of bash hacking to read the meta-data from the yaml block at the top of each article does the trick. I build a custom which will just turn into the bullet list I want after it runs through Pandoc. Makefile as a metaprogramming language 😜.

I also have a flag which allows me to hid WIP articles from the index, but let me continue commiting the html.

# Order is the index order. Maintain reverse chronological order.
    barcamp-2022 \
    make-a-static-site \

INPTUS = $(patsubst %,%/,$(ARTICLES)) $(INPUTS)
    @echo "---" >
    @echo "title: Blog" >>
    @echo "---" >>
    @for a in $(INPTUS); do \
        DATE=$$(grep -m 1 "date" $$a | sed -e 's/date: //g'); \
        TITLE=$$(grep -m 1 "title" $$a | sed -e 's/title: //g'); \
        PUBLISHED=$$(grep -m 1 "published" $$a | sed -e 's/published: //g'); \
        if [ $$PUBLISHED = true ]; then \
            echo " - <span style=\"color: #666\">($$DATE)</span> [$$TITLE](./$$(dirname $$a)/)" >>; \
        fi \

And there we have it! A flexible static website, with markdown for writing articles, but a light-weight set of tools to build the index and each page.