stupid index

The stupid setup of this stupid static site system.

I'm a simple human being. I don't need much. I see friend, I hug friend. I see carrots, onions, celery, tomatoes, tomato paste, soy mince, spices, pasta sheets, I make lasagna. I write blog, I want simple blog engine. I want it stupidly simple!

Simple means HTML and CSS. You don't need javascript for a blog 1.

Astro? I had to read trough 5 pages of documentation to see if it does static site deployment or if it's tied to a deployment server.
bear? I cannot host it myself.
Hugo? But does it... Yeah ok, Hugo has pretty much all I want.

You can see, nothing out there fits my needs. Plus it is fun to build, learn and architect.

The Requirements

Is there a list? Of course there is a list:

These requirements are already pretty exhaustive for a basic blog engine and I could call it a day here, throw the result behind an nginx and be happy. However, if I am already this deep in optimizations that no one will ever need territory, why not take on some extra challenge:

The journey

I am currently in between projects and in order to sell this little project as work time to my employer, I labeled it as education in AI driven development.

Claude joins the battle.

I started by hacking something together to validate my tech stack and see challenges early on. While I provided the tech stack and rough direction, I tried to micromanage Claude as little as possible. Overall, I was pretty disappointed with Claudes' abilities and the overall experience. I ended up writing most of the code myself. For those interested: I sort my thoughts about working with AI in this post.

The result of this first AI assisted PoC was a wanky rust executable that could replace variables inside an .html "template", another wanky rust executable that would generate the index, and a sophisticated Makefile, that would only rerender the necessary snippets.

Styling was done within a single .css file and oh boy, it was a pain to manage different page types like index and blog page within the same .css file. The Makefile however worked like a charm (pat on my back). However, it might have been overengineering.

Without compression, I even was slightly below 10kb!

I called it a week (mostly spent on the styles for the no-js menu and darkmode) and consolidated my approach.

After analyzing and refining my final architecture, I wrote down a README with my desired architecture and threw AI on the problem gave Claude another chance. It got half way and then just started to hump some dumpsters down the road. This was the point where I decided to take over and only use Claude for the very basic things, that only required a very narrow context.

The result

I ended up using jinja for templating and free template composition. All templates are stored in a templates directory, which is loaded in the beginning to populate jinjas template pool.

Styles are not handled by the engine/templating. Here I opted for a niche technology called css imports. It's rather complex but the short version is, you can import CSS in CSS. So if a template includes {% include nav_bar.html%} in its .html template, it must use @import "nav_bar.css" in its own .css file.

But Boi! Won't this result in loading the styles in sequence? Isn't that suuuuuper slow?

Page loading waterfall

Yes. Yes it is. If I ever run into the problem that high-frequency trading crypto bros need a faster pageload, I'll remind them of who the blog is for. And if I want to trade the benefits of the browser caching different styles at some point for faster page load for first time visitors, I still can bake them into my .html files... But this is a task for future Boi.

Getting back on track. Ehhh... Folder structure? Folder structure!

|- templates
|   |- blog.html # html jinja template
|   |- blog.css
|   |- nav_bar.html # html jinja template
|   |- nav_bar.css
|   |- index.html # html jinja template
|   \- index.css
|
|- assets
|   \- asset_1
|
|- content_files
|   |- blog_1.md
|   |- blog_2.md
|   \- ...
|
\- ...

While (changed) stylesheets and assetfiles are copied directly into an output directory, blog posts or other pages are generated from a file in the content_file directory. Content files contain a frontmatter; an area in the file to define variables in toml, as well as the content in markdown. Every content file must define its pagetype which is mapped to a same named template in which the content file will be embedded then.

In order to build an index of all blog posts, the process is multi step:

  1. Read all templates
  2. Read all content files (that have the property publish: true
  3. Build an index of all blogposts
  4. Render all markdown to HTML
  5. Resolve jinja templates
  6. Write to output dir

This allows me to use jinja templating in Markdown as well as in HTML. It further touches all .html files in the output and causes Make to consider them new. Stupid. After questioning my requirement on unnecessary recompilation, I decided to drop it for the time being. It's just incompatible with unchanged files that require changing metadata (like entries).

Another neat result of the entries variables being available for every page is that a blog post can easily reference its next or previous post. Furthermore, the index.html is just another content file that uses a different template.

Deployment

Since Claude seems to be very smart and I am just a simple stupid Boi, we had a bit of a disagreement here. Meaning I started to ignore Claude (again).

While Claude wanted to go the "copy files in a docker file to rebuild the container every time the files change" route, I deemed it more appropriate to just mount the output into the www directory of an off-the-shelf nginx container.

Because, you know, keep it simple stupid. Great advice. Hurts my feelings every time.

The rest is just as stupidly simple: Create a repository, mirror it to my VPS, create a webhook that runs git pull --rebase && make on said mirror for every main-commit. Lastly, a sprinkle of traefik labels for the right seasoning and voila, there is a 99.9999% up-time blog engine.

Conclusion

I am actually really pleased with the result. Especially the style management and matching content files to templates is stupidly simple yet effective. But the most important: I had fun. I have the feeling to own my blog. And while I am convinced that using and knowing large(r) open source solutions like hugo or jekyll and knowing their inner working is a valuable skill, it doesn't give me the joy of starting, building and finishing my first second real project in a while.

Footnotes

1

But Boi, how do you do interactive tutorials like josh? Well my friend. By using javascript in an interactive tutorial... But why should this static wall of text need javascript? Shhhhhhhh. It simply doesn't.

Im Übrigen bin ich der Meinung, dass die AFD verboten gehört.