My browser-based static site generator - stratts.au

5 min read Original article ↗

6 April 2026

This site can edit itself! That's not too surprising, as most websites have some sort of online interface to add content. The difference is that this is static site - hosted using Caddy's file_server. The editor, and site generation code, run entirely in the browser. Despite this, we have:

  • File browsing and uploads
  • Liquid templating
  • Markdown rendering
  • Image conversion/transformation
  • Live preview
  • .zip archive generation

You can edit this page right now! Just click the 'Edit page' button at the bottom (or this link). Make changes, delete files, upload images, whatever - then download the .zip and extract it to the root of your favourite web server. And then you can edit the site from there too :-)

I've had this idea for some time, but I had a few core requirements - namely the virtual file system and in-editor/on-site preview - and lacked the knowledge at the time to implement them in a satisfactory manner.

But why?

I have quite a strong desire to minimise dependencies, and there's a preservation aspect to it as well. I want to be able to leave my site, and build it again in 6 months, or 5 years. If I accidentally delete it, I'd like to be able to pull it from the Wayback Machine and just keep going! So no build system, no bundlers, no TypeScript :-(, nothing that will involve messing around with pip or npm.

Modern web development is generally a dumpster fire of constant deprecation and transient dependencies, but the web as a target on it's own? Everyone has a browser, backwards compatibibility is paramount, and it's fundamentally cross-platform. Seems pretty good for longevity to me.

But a big benefit was accessibility in the end - I really like the idea of static site generators, but it's just so tedious to open the terminal (or VSCode) to edit content. This post was written on my phone within the editor, and being able to just pick it up from whatever device I am currently using has been really nice.

How does it work?

The editor pulls the file list from _build.json at the site root, which contains a list of both content and generated (SSG output) files, with their corresponding hash and file size.

When a file is changed or deleted, a corresponding entry is added to an IndexedDB database. When the SSG fetches the file via vfs.get(), it'll check the DB first, then fall back to the live content.

The live preview works in a similar way: there's a service worker that intercepts all requests to /_editor/site-preview/*, and serves changed content from the DB (or returns 404 if deleted), and otherwise hits the live site.

So essentially, the preview endpoint merges changed files with content from the live site. We can revert to the live state by clearing the IndexedDB for that particular file.

The service worker also attempts to rewrite absolute links in HTML/CSS/etc files. So you can visit /_editor/site-preview in your browser to see a live preview of the built site, and references to images, etc, should all resolve to the preview version under that endpoint.

The site generator itself isn't too interesting, and a quick look over the templates should give you a good idea of how it works.

There is however quite a bit of logic around lazily fetching content, we're on the web after all! For example, rather than the SSG fetching and processing all images, it can detect whether they already exist on-site with the same hash, and fall back to that. The end result of this is that even though the SSG builds the site from scratch on editor load, it's only fetching the editor code + text content files + whatever is on the current page being previewed. So my site at least that initial editor load is 500KB - hardly small, but most of that is the 300KB CodeMirror bundle.

A quick note on LLMs

The whole process has been LLM assisted. I love writing code, so I feel some discomfort over this. But I'm a dad of two young boys, and this was all done from my phone when I had a spare minute... or a baby sleeping on me! This genuinely wouldn't have been possible for me right now without coding agents.

I have more thoughts about this that I won't put into words now, but so many bug fixes and performance improvements have been driven solely by me testing personally and prompting based on my understanding of the code.

Publishing

The primary method, if you have nothing else, is to download the ZIP. This will contain the content files + generated files + editor code, ready to extract wherever.

For my own purposes, in order to speed the workflow up, there's a very simple Python server, authenticated with an "API key". This just accepts a ZIP file containing the changed files, plus a _deleted.json to indicate deletions.

Content can be marked as drafts, so it gets saved on the server without appearing in the SSG output.

There's also a WebDAV and GitHub Pages backend - I got the agent to create these and they seem to work (neat!), but they're not tested thoroughly. In particular, the editor doesn't gracefully handle the lag between committing and when the live site updates.

May I use it?

I made this for me, a programmer who likes programming.

If you want to use this for your own site, go ahead! But this is not a battle-tested, stable piece of software - there are plenty of subtle bugs lurking in the depths of the code. Thankfully running in the browser means the damage can be limited, but I'd hate to see important content lost.


Thanks for reading!

This is my first blog post - hope you enjoyed it! More to come.