Migrating to YOCaml

Written by Reynir Björnsson, Nov 17, 2023

About a decade ago I created a blog on this website. It hasn't seen all that much use with about one post per year on average. Anyway, this article is not about how much or little I publish here. Originally I used Hakyll and I wrote about it in one of the first posts. It is written in Haskell, and you configure your web site using Haskell. This was great.
Then eventually my interest in Haskell dwindled to nothing and I no longer cared for maintaining the web site configuration. This was alright because the hakyll website binary was still there and I could use it to build my blog whenever I published something (which was rare).
Then I deleted all the Haskell bits on my machine in order to reclaim disk space. This was bad because then I no longer had the binary, and Hakyll had evolved and my project was no longer easy to build.

For several years I was no longer able to easily publish new posts on my blog. I had to manually edit html files whenever I wanted to publish something. It isn't all that bad to write html by hand - it's certainly doable if rather tedious. It was an unnecessary barrier to publishing.

Since I wrote the first post the functional programming language OCaml became my language of choice, and I work professionally with OCaml since a few years. I looked at a few tools in OCaml to generate static web sites, but none of them really enticed me. Sesame seemed promising to me at first, and the automatic rescaling of images and responsive images got me excited. However, I encountered several issues the author didn't seem so responsive to. Then my colleague @dinosaure introduced me to YOCaml! The learning curve was steep, and the library is written in a, in my opinion, unusual style for OCaml. After getting the hang of it I started to like it and finally I have migrated my website to a setup built on YOCaml. Hopefully this will be easier and more fun for me to maintain, and the frequency of posts will hopefully go up.

The code to process blog posts, at the time of writing anyway, is reproduced below:

open Yocaml
module Metaformat = Yocaml_yaml
module Markup = Yocaml_cmark
module Template = Yocaml_jingoo
let article_target file target = Model.article_path file |> into target
(* ... *)

let process_articles target =
  let open Build in
  process_files [ "posts" ] File.is_markdown (fun article_file ->
      create_file (article_target article_file target)
        (Metaformat.read_file_with_metadata (module Model.Article) article_file
         >>> Markup.content_to_html ~strict:false ()
         >>> Template.apply_as_template (module Model.Article) "templates/article.html"
         >>> Template.apply_as_template (module Model.Article) "templates/layout.html"
         >>^ Stdlib.snd))

Markdown files with their yaml metadata header are read, the markdown is converted to html using cmarkit in non-strict[1] mode, a layout.html template is applied after an article.html template is applied. This means I can write in markdown with some metadata such as publishing date and title, have the markdown-converted-to-html put into a consistent format with a header consisting of a heading with the title and information about the article. Then finally the super nice layout I stole from some other website is applied to every page has a consistent look.

On my TODO list for this website is to look into automatic rescaling of image and responsive images, and adding a feed. The former I suspect is less straightforward and may require some annoying processing. I expect it is not something I will achieve easily. The latter is more straightforward and I hope to get it done Soon™.

  1. Non-strict mode in cmarkit means commonmark extensions are enabled such as foot notes like this one.