Building a Website with Pandoc, Markdown, and Make

Joydeep Mukherjee

May 13, 2021 (updated May 5, 2022)

In this article, I describe a powerful approach to developing a personal website and blogging platform. I will introduce the specific tools I used, my reasons for choosing them, and my approach to designing a deployment system that is simple, fast, and highly customizable.

Requirements

I had a few requirements when designing my website:

Let’s address these one by one.

Inline \(\LaTeX\) and Code Snippets

Adding inline \(\LaTeX\) and code snippets would be pretty difficult in raw HTML and CSS. This is where Pandoc comes in.

With Pandoc, I can write in Markdown and export to HTML, specifying a custom template, stylesheet, and a bunch of useful extensions. Pandoc is extremely powerful and can convert between dozens of file formats, so I would encourage you to read the documentation to see what is possible.

Build System

To motivate the need for a specialized build system, let’s recall that we are using Pandoc to generate HTML files from Markdown files. The command to do so is:

$ pandoc ... -o file.html file.md

It would be a slow and tedious process to run such a command for every HTML file in my website, especially as the number of files increase.

This is where Make comes into play. This is a tool which builds files based on rules defined in a Makefile. It is especially powerful since it will not rebuild files which have not changed. It can generally be used by running:

$ make

Hosting and Deployment

GitHub offers a free static site hosting solution called GitHub Pages. This allows you to host a static site with a Git repository on your GitHub account. GitHub gives you a default URL, but you can add a custom domain (as I have). There are several other options for hosting available (i.e., a VPS), and this isn’t the most crucial factor in the design of this website, so use whatever you like.

Implementation

Let’s now cover the details of my implementation.

This is what my project structure looks like:

$ tree .
.
├── CNAME
├── Makefile
├── style.css
├── template.html
├── about.html
├── about.md
├── index.html
├── index.md
├── writing.html
├── writing.md
├── building-a-website.html
└── building-a-website.md

I will briefly discuss each file.

Stylesheet and Template

template.html is my custom HTML template for Pandoc. You can view the source for the default HTML template Pandoc uses with: pandoc -D html.

style.css is my custom CSS stylesheet for Pandoc (linked directly in template.html). Pandoc provides a great template and stylesheet out of the box, if you don’t want to set up your own.

HTML and Markdown Files

GitHub Pages looks for a file called index.html, which it treats as the home page of the website. index.md is its Markdown counterpart from which it is generated.

The Pandoc template houses the navbar, footer, and placeholders for metadata such as the title, author, and date of a specific page. This makes formatting extremely convenient and allows me to start writing the main content of a page immediately - almost no setup required. The Markdown source code for an article may look like this:

---
title: Building a Website with Pandoc, Markdown, and Make
author: Joydeep Mukherjee
date: May 13, 2021
abstract: ...
---

## The main content starts here
...
...

Makefile

As mentioned before, Make will look for a file called Makefile (or makefile) which contains the rules to build the project. Here are the contents of my Makefile:

PAGES=$(subst .md,.html,$(shell find . -name "*.md"))
OPTS=-s -f markdown -t html --template=template.html --mathjax

all: refresh

refresh: $(PAGES)

%.html: %.md
    pandoc $(OPTS) -o $@ $^

clean:
    rm -f $(PAGES)

PAGES identifies all the HTML pages that must be generated by Pandoc. To automate finding all these files, the find command first finds all Markdown files and then subst is used to replace the .md extenstion with .html.

OPTS identifies various options which are passed to Pandoc, such as the -s flag which produces standalone output rather than a fragment, -f and -t which identify the input and output file formats, --template which indicates the path to the template, and --mathjax which enables \(\LaTeX\) rendering in the output.

Most of the work happens in the %.html rule, where the pandoc command is called with $(OPTS) to generate each HTML file:

A clean rule is also provided, which clears all generated HTML files.

Deployment

In order to build and deploy changes to my website, I run the following commands:

$ make
$ git push origin master