Rolling my own static site generator
Man this blog was a long time coming. For the past 5 years I’ve always wrote myself little articles, notes and journal entries and I’ve always wanted to have a central repository where I could store them.
Now we’re here. But the journey has been tough.
Episode 1: html+css (2023)
I made a crappy blog in 2023, using just raw html + css. It was a fun learning experience, but a horrible display of my skills. For some problems:
-
adding new pages is irritating. I need to create the page then update every link on my site. I shouldn’t have to change 2 things every time I want to make a blogpost (its trivially easy, just annoying).
-
styling is also annoying. I use a lot of custom html+css and it’s tedious to update (I have a bunch of repeated styling code, I can change the css well enough - but larger changes involve me editing every single page).
-
I can use blank templates and AI, but the templates become out of date and AI tooling was garbage then. I also wanted to learn instead of rely on AI.
-
Dynamic Theming is super hard.
Episode 2: Astro (2023-25)
In the Greensboro Developers club, Astro is extremely popular. We had a few people chat about it, and I’ve learned a lot about using it in different contexts (blogging, CMSes, portfolios) but MAN this was hard to use.
My javascript skills are on the lower-end, and my js framework skills are practically non existent. Astro is good, the documentation is nice, but I felt like I was hitting my head against the wall constantly.
This may just be a skill issue - but trust me. I’ve tried multiple times to get good at Astro. Following youtube tutorials, using AI, using templates - none of it worked for me.
To put it plainly, there was never a point when I grokked Astro. Sure, I can explain to you how hydration, tagging and dates all work together - but if you ask me to add tailwind css to my project, I’ll fail.
Like with Godot or Unity, it’s trivial for me to create scripts to get things running. It’s easy to conceptualize that I have an object, I attach scripts to it, and I change the properties / functionality. For Astro, the framework gets in the way IMO.
Case in point: Dynamic tag routing in Astro. In a typical python program this is trivial.
-
Read through list of documents
-
parse the header metadata (can seperate document into lines, find the line with :tag: and read it)
-
Get the tag and put the document in a certain bucket
-
Now when the user wants to see elements with a tag, show them the bucket of tags
Just a basic for loop.
[.line-through] Meanwhile in Astro Source
Okay. I stand corrected. It’s actually a lot easier than I thought. But still, I found it to be extremely complex because I’m working with the auxiliary framework and setting it up how THEY want. I don’t understand the reasoning of why they set up the framework this way, the tradeoffs, and how to implement it myself.
I just want to liveblog something and get it out there easily. But I was given an extremely strong tool with hydration and islands. Astro is good, but I could not, for the life of me, understand it.
Episode 3: Sveltekit static site (2026)
I’ve been learning Svelte outside of work for a few months now, and I really like it. I feel extremely productive. I would’ve stuck with it but I ran into the same issue as Astro.
I felt like I was working with a framework, when I really should’ve been making my own.
Finale: This site.
The pipeline is simple.
-
Create asciidocuments in /content
-
Create Jinja2 compatible templates in /templates.
-
The main one i use is called base.html.
-
-
Create main.css for the page layout
-
Create theme.js for the theming
-
Use the main python program
-
Call Asciidoctor to convert asciidoc pages to .html in a forloop
-
Combine the .html with Jinja2 to convert it to a themed, detailed webpage
-
-
Deploy
Now - with that being said - the last two asciidoctor and jinja2 steps are doing a LOT of heavy lifting here.
Firstly, the jinja templates automatically just pull in my header, footer and side boxes. This is super easy for me to do.
The asciidoc → html → jinatemplate injection → final page pipeline is trivial.
The hard part is the index and tag buckets. These are dynamic pages, so I need to take a baseline, and then iterate over in a for loop. My solution is ugly. We don’t do pagination or reactive routing. I just hard write them to the page.
I also hard write the tag buckets to their own pages too.
Now, a benefit is that when I check tags in the asciidoc, it was simple.
-
Include code block for getting tags from :tags: section
-
Append the title and page to the tag page
-
Append to blog/microblog page
-
Append to the home page
I did have to touch some advanced javascript with the themes. Instead of using a cookie for the themes, I used a URL hash instead.
The hardest part was the CSS. I had to use AI for help.
I know it’s in bad spirit to do so - but I’m going to be honest. I was so done with this project, and getting the boxes looking just right was taxing on my sanity.
Why Asciidoc?
I made a bunch of posts in markdown. It worked perfectly fine, but I saw someone mention Asciidoc on HackerNews and I got intrigued.
I’m going to be honest - the change was minimal. I just have the reference documentation up on my second monitor and get to typing. It’s trivial.
I don’t even use any of the advanced Asciidoc features bruh. I just type in it.
I’ll feel differently as I use this more.