Building a Static Site Generator From Scratch
Every time I try to start a blog, I got bogged down in the framework, theming, etc... everything but writing actual blog posts. Eventually I get frustrated at the lack of simplicity for what i see as a simple thing, and abandon the project. Not this time though. This time, I was over frameworks that felt too complciated for what I wanted to do. I don't need access to 5k plugins and 20k templates. I just need a simple blog that can put my thoughts online, and on my own server.
My Main Requirements
The system had to have a few things:
- Be able to accept raw HTML as a blog post (no special tags to work around an interpreter).
- A Minimal (or no) db. I settled on HTML files with YAML front matter (because simplicity), plus I don't need to open anything but the blog post html file to see all the information I need.
- Render them through templates - I wanted to be able to quickly swap design if I felt like it. Laravel offers blade templates so that was simple.
- Generate a static site I could deploy anywhere. Minimal server requirements. No composer, node, etc... even cheap shared hosting must satisfy.
- Include an RSS feed and basic API, for syndicaing relevant posts to different places, like my main site.
- Be build in such a way that it's easily extendable when I do want new features.
Implementation
I chose Laravel as the local tool, somewhat out of habit/preference, but also for Blade templates and Artisan commands. The structure of the application is pretty simple and The build process is straightforward: parse posts, render through templates, write to disk. Pages are basically static html/css with minimal js where necessary.
blog_content/
posts/ # HTML files with YAML front matter
templates/ # Blade templates + CSS
rootwork/
style.css
index.blade.php
post.blade.php
tag.blade.php
partials/
header.blade.php
footer.blade.php
images/ # Per-post images
{slug}/
hero.jpg
assets/ # Shared images, fonts, etc.
dist/ # Generated static site
config/blog.php # All configuration
app/Extensions/ # Extension classes (just in case)
public function build(): array
{
$posts = $this->postService->all();
foreach ($posts as $post) {
$html = $this->templateService->renderPost($post);
file_put_contents("dist/{$post->slug}/index.html", $html);
}
}
I really like this build process because it just sort of gets out of my way. I write each post in raw html and push it throgh the build process where it gets dropped into my template and then added to the static site. deployment is just uploading a single folder over scp/rsync. I'm quite happy with how it turned out :-)
What I Learned
The code was the easiest part, once I figured out a structure that seemed intuitive. Then, how to render to static files in the way I needed to.
Deciding what to leave out was a bit of a challenge. I noticed I kept reaching for standard paradigms that I didn't really need, just out of habit. In the end there's no comments, no analytics, no social sharing, etc. Just words on a page, rendered fast and served from a simple web server. Maybe I'll add comments or something later, but for now it's just me, screaming (softly) into the void, for my own sake.
Sometimes the best features are the ones you don't build... or something profound like that haha