How the blog works

[note] This post was requested by a cutie <3

I wrote a sort of blog engine for my site, because I love reinventing the wheel.

How

There's a folder called blog/ where each blog post has two files: post.md and post.toml. The blog post can then be accessed by requesting /post.md from the browser.

Adding a blog post is simply a matter of creating a markdown file with the desired page name, and a metadata TOML file with a title, a summary and a creation date grouped under a table named "meta":

[meta]
title = "How the blog works"
summary = "This post explains how my blog works in more detail."
date = 2022-02-19

I also encourage you to take a look at the source code!

Index page

The index page, served at /blog, constructs an instance of the Blog type by loading all .md files in the blog directory. For each of those files, the extension is stripped and the request handler attempts to open the .toml with the same file stem (file name with file extension stripped).

If opening the .toml file fails, or if there is no .md file for a .toml file, the post does not appear in the blog index.

The metadata is loaded from the .toml file, including the title, summary and date of the post. The summary is currently unused in the index page. The title is put as the content of the link to the post page, and the date is used to sort the posts by recency.

Post pages

The posts are served at the name of the .md file holding their contents. The library I'm using, comrak, has a nice convenience function for parsing markdown and converting it to a string of HTML, which saves me so much effort (and thus, complexity). When a client requests the blog post, the file is read and the contents are rendered as HTML.

They are then wrapped in an <article> tag. This is for multiple reasons:

  1. It makes sense, semantics-wise;
  2. It allows me to create CSS rules specific to the body of blog posts.

RSS feed

The RSS feed is generated from the .toml files, aggregating the 20 latest posts into a channel and turning it into XML. For this task, the handler also constructs a Blog struct that holds a list of all valid blog posts, so posts without content or posts without metadata are not listed in the feed.

Why

Because it's simple, and I like it simple. It also plays very nicely with existing tools.

Workflow

For example, I use git to manage both the code of my site and its content. This includes the content of my blog. Re-indexing the blog/ directory every time someone requests the index page makes it so that I can git pull my blog post to my server and have it be accessible instantly without needing to restart the entire server or whatever. I can use any editor anywhere to write blog posts, as long as I can do a git push to my repo.

Special/important blog posts can be made in a separate branch and reviewed, which could be useful.

Markdown

The posts themselves are written in markdown because it's so much easier to write than HTML. The comrak library provides an easy function to convert a String of markdown to HTML and it just simply works and I'm not complaining.

Most importantly, I don't have to use some weird web interface or ssh into my server to write the post. I can just do it with my normal editor. Wow! Revolutionary!

TOML

The metadata uses TOML because I think YAML and JSON both kinda suck. I have my issues with using TOML for anything that isn't, like, a small set of trivial key-value pairs but for this, it's pretty much a perfect fit. It has a built-in date type and that comes in handy, too.

The reason I am using a separate file for the metadata is simple, really: it keeps the metadata away from the content of the post, but also doesn't rely on the quirks of the file system itself. Also it's easier because this way I wouldn't have to figure out how to extract YAML metadata from a comrak markdown AST instead of just converting the markdown to HTML and directly serving it.

The first iteration used the creation time where the current system uses the "date" value and to be honest that was just a disaster waiting to happen. Using a real file allows me to extend the system to allow me to define tags for a post in the metadata file without too much effort, which is a feature I might want to implement later.

Final remarks

I had a lot of fun writing this part of my site, and I really like the final design of the whole system. It's lightweight, but also extensible, and it feels well-rounded.