Welcome to my new personal website! I’m finally staking my claim on the World Wide Web1. 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
    testing things out :wink:

<!-- 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 ()
main = hakyllWith hakyllConfig finleyDev

hakyllConfig :: Configuration
hakyllConfig =
    defaultConfiguration
      { providerDirectory = "data"
      , previewPort = 7220
      }

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!


  1. Don’t worry, I promise to keep the emoji usage to a minimum. Just testing things out 😉↩︎

  2. 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.↩︎