Welcome to my new personal website! I’m finally staking my claim on the ✨World Wide Web✨1. It took me a while, but I’m quite happy with the end result. I will be using this space primarily to blog about software development and post photographs I take. For this introductory post, I thought I’d describe how I built the site. This post will serve partly as documentation for my future self, and partly as a tutorial for anybody interested in implementing their site using similar tools.
Introduction
This website is completely static, meaning there is no server-side logic. It is completely hosted on a boring old file server. The interesting bit just revolves around how the files are created, organized, and then accessed by the file server. To explain that, I’ll walk through precisely how the HTML content you are seeing right now reached your browser.
Markdown
It probably won’t surprise you to learn that I, as a Haskell developer, prefer to avoid writing large amounts of raw HTML whenever I can. Thankfully, there’s a very nice piece of software named pandoc (which just so happens to be written in Haskell) that makes it easy to avoid such unpleasantries. Pandoc can convert pretty much any markup format into another. The pandoc website puts it best:
If you need to convert files from one markup format into another, pandoc is your swiss-army knife.
I’ll explain exactly how pandoc fits into the pipeline later. For now, at a high level, it means I can write these posts in pretty much any markup format I please. The one I prefer to use, and the one I’m writing this in right now, is called Markdown. For example, this is what the source content of this post looks like up to the end of the introduction:
---
title: My new website
header: A website appears! Or, how to make your own blog using Hakyll
subheader: Introducing my new personal website, and explaining how I built it
toc: true
tags: haskell, meta
---
Welcome to my new personal website! I'm finally staking my claim on the:sparkles:World Wide Web:sparkles:[^emojis]. It took me a while, but I'm quite
happy with the end result. I will be using this space primarily to blog about
software development and post photographs I take. For this introductory post, I
thought I'd describe how I built the site. This post will serve partly as
documentation for my future self, and partly as a tutorial for anybody
interested in implementing their site using similar tools.
[^emojis]: Don't worry, I promise to keep the emoji usage to a minimum. Just
:wink:
testing things out
<!-- more -->
# Introduction
This website is completely static, meaning there is no server-side logic. It is
completely hosted on a boring old file server. The interesting bit just revolves
around how the files are created, organized, and then accessed by the file
server. To explain that, I'll walk through precisely how the HTML content you are seeing right now reached your browser.
Syntax
The beginning chunk, between the ---
markers, is called front matter and it
is not considered “standard”2 Markdown. The information held in the
front matter is only used by the renderer to change how certain elements are
translated. For example, pandoc supports a toc
front matter
item which determines whether the resulting document
should include a table of contents. All of the content that follows the front
matter is just pandoc-compatible Markdown, which is documented
here.
Organization
I keep the Markdown files holding the content of these blog posts in a single
directory. Their names follow a YYYY-MM-dd-title.md
format. For example, this
file that I’m writing right now is named 2023-09-26-hello-world.md
.
Hakyll
A devoted masochist might decide to manage their site’s content by manually running pandoc on each of these Markdown files and uploading the resulting HTML to a file server whenever the source content changes. I lack such a pain tolerance, and it’s quite difficult to share/replicate content across pages using this method. For example, every time I wrote a new blog post, I would need to update the list of my recent posts on the index page.
This is where static site generators really make themselves useful. Static site generators allow users to create document templates which get automatically populated with content resulting from things like Markdown files. Some examples of popular static site generators are Hugo and Jekyll. For my website, I chose to use one called Hakyll, because it allowed me to fully and easily customize the generator as a Haskell program. Furthermore, since Hakyll uses pandoc, I can fully customize the document translation process by accessing the pandoc abstract syntax tree (AST).
The Main
module of my site generator is tiny:
module Main where
import Hakyll
import Gen.Rules
main :: IO ()
= hakyllWith hakyllConfig finleyDev
main
hakyllConfig :: Configuration
=
hakyllConfig
defaultConfiguration= "data"
{ providerDirectory = 7220
, previewPort }
That hakyllWith :: Configuration -> Rules () -> IO ()
function is what
actually does the site generation, based on the given Configuration
and Rules ()
values. In my Configuration
value, I specify that my site data is stored
in the data
directory and that I want the preview server to run on port 7220.
The Rules ()
are where things actually get interesting.
Rules
In progress!
Don’t worry, I promise to keep the emoji usage to a minimum. Just testing things out 😉↩︎
Markdown has no “official” formal specification. It’s syntax is only specified by the supported syntax of the renderer being used, although many popular renderers support something like the extended syntax as described here.↩︎