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.
I had a few requirements when designing my website:
Let’s address these one by one.
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.
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
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.
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.
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.
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
... ...
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
$(OPTS) -o $@ $^
pandoc
clean:
$(PAGES) rm -f
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:
$^
identifies the input Markdown file. In Make,
$^
refers to whatever is after the colon in the
rule (i.e., the dependency)-o $@
identifies the output HTML file. In Make,
$@
refers to whatever is before the colon in the
rule (i.e., what is being built)A clean
rule is also provided, which clears all
generated HTML files.
In order to build and deploy changes to my website, I run the following commands:
$ make
$ git push origin master