Mewsse

🏳️‍🌈 Mewsse

My small personnal blog, where I will try to post more articles about things

How it was made ?

Since the launch of my blog, a lot of friends asked me how it works and what's used to make it run or how the comments system is working. So here it is, a small how it was made ? article to explain everything if you are curious !

Small recap

I didn't want to use anything like WordPress (even if I work with it, like for Furry FR1) for my blog. I wanted something very light without a backend and easily self-hostable.

I also wanted something personal, just to learn a thing or two and unrust my skills, because it's been a long time since I really developed something for myself (talk about a big lack of motivation). So Hugo, Jekyll or 11ty were out the window for this project. I needed to do it myself.

This is the result, an easy to work blog with statically rendered files, only composed of HTML, CSS and a little of Javascript2 for the comment section (more on that later). As it's fully rendered as static html, it's served with a small Nginx instance and can be easily cached by a CDN or whatever you are using. Use markdown, push to main, profit.

vscode
yes, it's this article being written

So, how does it work ?

Nothing very fancy: the code is written in javacript and running on Node.js 22. It's only using a small list of npm packages (for template rendering and markdown parsing/rendering) and nothing more. It's a modified version of the same code that run mewsse.gay, with more options and flexibility.

You can check the single file containing all the code (because why not, eh ?) and everything can be launched with npm run build or npm run serve if you want to see the result locally.

Everything is rendered in the dst directory, you can copy it wherever you like, spin up a small server to expose it to the interwebz and you're done!

How to use

A small config file is present at the root of the project, allowing quick editing of global configuration variables:

{
  "title": "Mewsse's blog", // default title of the blog
  "description": "Here comes a description", //default meta and og description
  "url": "https://mewsse.lgbt/", // root url, useful for the atom feed and open graph
  "image": "https://mewsse.lgbt/assets/favicon.webp", // default image used in the open graph
  "itemPerPage": 5, // number of posts per page
  "itemOnAtom": 20 // number of posts in the atom feed
}

All posts are contained in the posts directory and if the post is in a self named directory, all files adjacent to it will also be copied with the post, permitting inclusion of anything in the document, like the image of this article.

Posts use the Front Matter format, like Jekyll, to set variables for the post (title, description, date...) used for the rendering part.

---
title: Hello World !
description: Hey, I'm Mewsse ! Here I will talk about stuff and things, I don't know. Also, how did you get in ?
date: 2025-05-12
tags: ["tldr"]
image: header.webp
---

A feed is also auto-created, because RSS/Atom is still used, and all open graph metatags are also generated for each post, permitting easy integration on any service that know how to read them.

I even automated the build part with a gitea act runner running locally on my server. A single push on main and bam, update is live!

And for the comments ?

Comments are 100% rendered client side !

When I publish a post, I also publish the link in my bluesky. I then copy the link of the bluesky post and edit the front matter part of the post to add a bluesky property :

bluesky: bsky.app/profile/mewsse.pet/post/3lphoozf3q225

A small script calls the bluesky public API to get all replies and render them using a HTML5 template element3! To post a comment, just reply to the bluesky post ! I also added a custom blocklist as I can't call the graph to get all accounts I block... If you're on the list, sorry not sorry.

Footnotes

  1. Furry FR is an association for furry fandom enthusiasts in France that I'm volunteering for.

  2. no cap on the S. Nope. I don't want it.

  3. An element holding an HTML fragment that can be used via javascript, more on MDN.

Comments 🦋

Post a comment by replying to my Bluesky post!