🔥 Sudhanshu Raheja's Log

The Eternal Cycle of Static Site Generators and Yak Shaving

2025-01-28

Making a simple static site generator because learnings someone else's top class code is harder than writing something silly on your own

There are 3,826 public repositories on github tagged as static-site-generator and yet I wrote a new one this weekend.

My history with static site generation repeats itself a lot. Every 12-24 months, during the holidays, I get the inspiration to start running and to set up a site to document more of my life. And every attempt starts with trying to discover the best tool to use, and with so many world class tools our there, the trial process would usually last till the last day. By the end of the holidays, I would have found something I liked, migrate the 5 old posts to the new tool, and deployed them somewhere, but there was no more time left to start writing a new post. If yak shaving was a olympics sport, I would be a medal contender.

So this time, I decided to drop both Hugo and Astro, which had won the previous rounds of static site generators trials, and decided to write a new one.

Scope

The scope of the project was straight forward. I love using Obsidian, I decided to migrate the older posts to a new vault, and use that as my admin portal to write the posts. It has great support for writing in Markdown as well as adding meta in frontmatter.

The goal of the project was to create a simple static html generator, which would take this vault and convert it into a site.

Blog post view on Obsidian

Implementation

Typescript

I decided to start with either Typescript or Go, mostly because I didn't want to start learning a new language. Having a fast build time wasn't really a concern, given my history of not writing too many posts, so I dropped Go, and had only one option left.

Markdown

Nothing beats the simplicity of Markdown, and because of Obsidian, I deal with it day in and day out, hence Markdown was a clear choice.

HTML, CSS and Vanilla JS

For all client side components, I decided to use HTML, CSS and plain vanilla JS, to cut down on further learning curves. I had built the frontend components of my last project - Dictionary - using Svelte, which was pretty awesome. However, I can never go back to the project again because I have completely forgotten what's written there and there's now Svelte 3. HTML, CSS and vanilla JS haven't changed at all in the last 10 years (some would say unfortunately, but fortunately for me), so all I needed were some DeepSeek prompts to get me started again.

DeepSeek

ChatGPT had replaced Google as my primary search / research tool about a year ago, but given all the hoohaa about DeepSeek, I decided to try it out this time. Other that the frequent downtimes that cheapsters like me should expect for using an awesome free tool that I'm not hosting myself, it was pretty awesome.

Sqlite

While most of the site would be a static HTML, there were two parts which need an API - search and tags. Hence instead of trying to wrangle with HTML, I decided to push the posts to sqlite and build an API to query.

Other Libraries

I needed something light for the APIs, so I picked Hono. For templating, I used EJS because it allowed me to use JS inside the templates. Remark was the best option for converting Markdown and finally used Sharp for compressing the images.

Docker

Last but not the least, I used Docker to create the container via Github Actions which runs on the server. There's no CI/CD, so I have a small makefile to pull the latest container and re-run the container.

Deployment

I picked up an unbelievably cheap server at RackNerd and have been using it for all personal projects. It's a simple set up with domains proxied via Cloudflare, Caddy fronting everything, and each site runs as a container. The logs end up on a free account with NewRelic.

Wrapping up

Lastly, I ran a quick load test with k6, to ensure it doesn't go down if someone comes to read.

Load test results

The results aren't too bad. Average response time at 207ms is a little slow, but P95 is very close to P50. Connection time is taking forever, so that's something to lookup in the future. Running 40 rps on a $6/month server with a bunch of other stuff, seems good enough.

Overall, I started with a new repo, and ended up deploying this post, so the project is really done. As long as I can keep coming back to write, it feels like time well spent.