Spot an error? Know how to make this page better? I appreciate pull requests.

Generating this website

Literally, literate

This site is generated using Hakyll, a Haskell library for generating static websites. The raw version of this file (see the source link at the bottom of this post) is compiled into the executable that generates this entire site, and in turn is presented as this post. This is achieved by writing a literate source file.


This is not intended as a beginner tutorial, so some working working knowledge of Haskell is assumed going forward. As with all Haskell files, we have to import some modules.

First we import the Hakyll module, which contains the core functionality needed to generate this site. Next import is Hakyll.Web.Sass which provides a compiler for scss.

Next is the Monad module, which facilitates composition. If not familiar with function programming concepts, it is worth looking into.

The Data and System modules provide many of the common functions you would expect in a programming language.

Finally we import some UTF8 encoding to keep things consistent.

Now that we have everything imported we can set some configuration. The providerDirectory is where the built executable will look for source files when building the site. By putting all the files in a sub folder we can keep root folder clean.

Here we define the patterns we use to find content

A ‘post’ is an article that is ready to be published and included in the sites feed and listing. Grab anything, no matter how deep in the post directory, regardless of the file extension.

A ‘draft’ is an article I am working on, and want rendered, but to not include in any listings. It can be accessed by providing the direct URL to the page. This is useful if I want to provide someone the ability to proof the post before going live. Grab anything, no matter how deep in the drafts directory, regardless of the file extension.

notes whatever, so I can organize as I see fit.

Instantiate hakyll with UTF-8 encoding the above configuration.

First we need to render our templates so we can apply our content onto them.

Each of the following lines generates a portion of our content. More detail will follow when we look at the function definition.

I am using normalize.css, along with a syntax.css file, these get copied directly to the output directory.

todo: hakyll-sass

The following files are just copied verbatim due to the idRoute and copyFileCompiler combination.

index has some unique things. Lists of most recent posts, and list of most recently updated notes

todo: context todo: relativizeUrls todo: removeIndexHtml

Next we build the static pages. They live in the subfolder pages, strip that from the url. compile the markdown with pandoc. Drop them into the site template

Create the notes index page lexicography Ordered needs a title

The typical ‘archive’ page is just /posts, a list of all posts. One day, when I write a lot, I’ll need to figure out pagination

todo: posts and notes are treated the same. Just a logical separation .||. is logical OR for the match

While I strive to keep everything open and transparent, some things are secret. These I store in a private git repo and clone it into a folder named secret under provider.

First we create the secret pages.

As with the static above, just blindly copy everything in the secret folder to the site root. Allows me to host any files arbitrarily. todo: explain gsubRoute

todo: contexts, what is it?

todo: make the below two functions into one

todo: git things

The url to an items commit in GitHub

The url to the item at the current time.

Todo: pull current branch out, so links where when I’m in local dev mode.

todo: combine functions

– todo: below –

todo: consolidate the below functions

OK, after that little detour, let’s get back to it! The dateAndTitle function above made use of two helper functions which haven’t actually been defined. The first is readTime, which we use to normalise the date format. It takes a date string and converts it to a UTCTime which we can manipulate.


The basic idea for the implementation is taken from Hakyll itself, from its getItemUTC which is defined in [Hakyll.Web.Template.Context][hwtc]. Unfortunately, the type signature for that function is quite a lot more complicated than we need, so I’ve extracted the parts we need into a simple String -> UTCTime function here. If the date doesn’t match any of the supported formats readTime will simply crash with an error – not the best error handling but since we’re always going to be running this interactively it doesn’t really matter.

setBaseName turns a string into a FilePath, which it can then manipulate using Haskell’s native replaceBaseName functionality.