The current Hakyll build script

I’m fairly sure I understand the current build script, and it seems to be rather minimal. Hopefully it can serve as an introductory for someone who, just like me, is new to Hakyll.

The site layout

Before getting into the build script it’s worth describing the folder layout of the project, it looks like this:

├── build_site.hs
├── index.html
├── posts
│   ├── 2014-09-23-000-moving-to-hakyll.mkd
│   └── 2014-09-23-001-hakyll-build-script.mkd
└── templates
    ├── default.html
    └── single-post.html

The templates

A template for, as the name suggests, a single post. It renders the post into an HTML snippet.
The main template, i.e. the one that provides the entire structure of a complete HTML page.

It should also be noted that index.html basically is a template itself. These three files fit together such that each post is turned into an HTML snippet (single-post.html), all the snippets are then pulled into index.html, which finally is wrapped into a proper page by default.html.

The script

The full script looks like this:

#! /usr/bin/runhaskell

{-# LANGUAGE OverloadedStrings #-}
import Data.Monoid
import Hakyll

main :: IO ()
main = hakyll $ do
    match "posts/*" $ do
        route $ setExtension "html"
        compile $ pandocCompiler
            >>= loadAndApplyTemplate "templates/single-post.html" baseCtx
            >>= saveSnapshot "posts-content"
            >>= loadAndApplyTemplate "templates/default.html" baseCtx
            >>= relativizeUrls

    match "index.html" $ do
        route idRoute
        compile $ do
            posts <- recentFirst =<< loadAllSnapshots "posts/*" "posts-content"
            let indexCtx =
                    listField "posts" baseCtx (return posts) <>
                >>= applyAsTemplate indexCtx
                >>= loadAndApplyTemplate "templates/default.html" indexCtx
                >>= relativizeUrls

    match "templates/*" $ compile templateCompiler

baseCtx :: Context String
baseCtx =
    dateField "date" "%Y-%m-%d" <>
    constField "site-title" "Magnus web site" <>
    constField "site-subtitle" "Random stuff" <>
    constField "author" "Magnus Therning" <>

The only slightly unnecessary thing is that all posts are turned into complete web pages (line 14), but none of those files is actually reachable from the generated landing page. My plan is to limit the number of posts on the landing page so they will be used later on.

For the moment some site constants are put into the base context. I’m not completely convinced that’s the wise thing to do, but I have a vague feeling that it’s better putting stuff like that into the context than hard code them into the template. I guess the better solution would be to have a configuration file for them though. That’s for the future though, for now I’m keeping it simple.

Leave a comment