A few posts ago I mentioned that I’ve been thinking about how commenting and static sites currently fit together.

There are already commenting services that can be used on static sites — services like Disqus and Muut — but I’ve yet to come across one that doesn’t require a large JavaScript file to not just work well but work at all. I want a system that won’t cripple performance. One were you load a page and the comments are already there, baked into the HTML.

I haven’t written any code yet, but I jotted down some thoughts on how this might work a couple of nights ago. What follows is an expanded version of those notes.

Note: I don’t currently have a name for this thing, so for the sake of this post I’ll refer to it as Honeydukes.

Platform

I want Honeydukes to be easy to install and have a small footprint once it’s running. It will come as no surprise to anyone familiar with this blog, therefore, that I’ll be writing it in Rust. The main reason why (other than it being my preferred language) is that doing so means Honeydukes can be distributed as a single executable. There’ll be no database component either, making the installation process a breeze (hopefully) with no need to setup some special environment for it to run.

Relationships

I started by mapping the relationships I could think of that are present in a commenting system.

For starters, a comment needs to know which post it belongs to. There are various ways of doing this. Having a uuid in the frontmatter of each post seems like the most straightforward solution though. Adding one to each post on a site is easily scriptable, meaning that a user won’t have to go through each post one-by-one adding a uuid key/value to its frontmatter. It also avoids identifying a post by something potentially more variable like its slug.

How will a post access its comments? Both Hugo and Jekyll (and others I’m sure) have the concept of a data directory which is accessible by all of the templates in a site. Each post will have a file created for it in the data directory containing all of its comments. The name of that file will be the uuid in the posts frontmatter, making it easy to identity.

Next, a comment needs a way to be uniquely identified for things like editing and deleting. We also need to know the name of the person who wrote it and the time at which it was submitted. Easy: uuid, author and timestamp key/values. I might also add a human readable version of the timestamp so that someone implementing this doesn’t have to do any jiggery-pokery if they don’t want to. Something like human_datetime perhaps.

In any system worth its salt, you can reply to comments. I think the best thing to do here will be to give each comment a replies key, the value of which will be an array of comments. Such a structure should make it easy to render the replies to each comment in the order in which they were submitted.

Piecing the above together, the comments file for a single post should look something like this:

[
    {
        "uuid": "some-uuid",
        "timestamp": 12345678,
        "human_datetime": "Aug 12, 2017 at 12:58",
        "author": "Elliot Jackson",
        "value": "The contents of the actual comment",
        "replies": [
            {
                "uuid": "some-uuid",
                "timestamp": 12345678,
                "human_datetime": "Aug 12, 2017 at 12:58",
                "author": "Elliot Jackson",
                "value": "The contents of the actual comment",
                "replies": []
            },
            {
                "uuid": "some-uuid",
                "timestamp": 12345678,
                "human_datetime": "Aug 12, 2017 at 12:58",
                "author": "Elliot Jackson",
                "value": "The contents of the actual comment",
                "replies": []
            }
        ]
    },
    {
        "uuid": "some-uuid",
        "timestamp": 12345678,
        "human_datetime": "Aug 12, 2017 at 13:50",
        "author": "Elliot Jackson",
        "value": "The contents of the actual comment",
        "replies": []
    }
]

Closing notes

  • This is specifically designed for static sites that are self hosted. It won’t work for sites hosted by GitHub Pages for example. If you’re using GitHub, I’d recommend checking out Staticman. I haven’t used it myself but it looks pretty good.

  • “What about spam?” is a question that may well have popped into your head whilst reading this. Simple answer: Akismet API.

  • I haven’t given a huge amount of though to “nice” moderation. The structure of the data is such that you can simply delete a comment object in the appropriate JSON file without repercussion though.

  • This site gets regenerated every minute via a cron job (more about this site’s setup), so comments will take, at most, a minute to appear for other readers. Hardly elegant, but this will probably be the recommended setup for others too, at least initially.