Wytchcraft
This week and into next I'm on a little getaway. It's not a full break from work, though I am working a bit less this week. I'm off in coastal cabin with Amy and Roxie. We're staying a short distance from some of the best surf spots on the South Island. I'm taking full advantage of being a few minutes from the surf, rather than 1.5 hours.

The season of the Wytch continues, despite having more client work on my plate right now. The goal is to move both the Super Good website and my personal site to it eventually. Is it wise to use a bespoke static site generator in production? Absolutely.
Surely you're not going to tell me you don't know at least one person who builds their personal site with Makefiles or some more esoteric system. I happen to know John's website was Makefile-driven until he decided he could make the builds near instant by using Rake. (Using Rake saved on the startup cost of repeatedly shelling out to Ruby.)
My personal site has been driven by a ton of things over the years. I've used Jekyll, Gatsby, Rails, Rack, Next.js, Middleman, Nanoc, and probably more that I can't think of right now. Oh yeah, a Makefile. I've been there too.
More Code-Reloading
One thing I've been working on getting just right is Wytch's code loading. I'm still not sure the abstractions are exactly where I want them, but what I've got is reasonable.
Separate listeners track the changes to both the site code (loading by Zeitwerk) and the content code (which we load ourselves).
module Wytch
class ReloadCoordinator
attr_reader :reload_lock
def initialize
@reload_lock = Concurrent::ReadWriteLock.new
@site_code_dirty = true
@content_dirty = true
@start_site_code_listener = Once.new do
Listen.to(Wytch.site.site_code_path) do
@site_code_dirty = true
end.start
end
@start_content_listener = Once.new do
Listen.to(Wytch.site.content_dir) do
@content_dirty = true
end.start
end
end
def reload!
@start_site_code_listener&.call
@start_content_listener&.call
return unless @site_code_dirty || @content_dirty
reload_lock.with_write_lock do
if @site_code_dirty
# Site code changed: reload site code then reload content
@site_code_dirty = false
Wytch.site.site_code_loader.reload
Wytch.site.load_content
elsif @content_dirty
# Only content changed: just reload content
@content_dirty = false
Wytch.site.load_content
end
end
end
end
end
That class handles all the heavy lifting. A simple middleware consumes that object, telling it to reload on each request (which only does something if the code has changed).
module Wytch
class SiteCodeLoaderMiddleware
def initialize(app, coordinator)
@app = app
@coordinator = coordinator
end
def call(env)
@coordinator.reload!
@coordinator.reload_lock.with_read_lock {
@app.call(env)
}
end
end
end
I want to pull more abstractions out of the ReloadCoordinator. The repetition in the Once blocks is screaming to be pulled out. Maybe the coordinator doesn't even need to know about Listen at all. We'll see.
Vite Integration
Besides supporting static files (put them in public/ and they will be served by the development server and copied into the build folder), I also threw together a basic Vite integration that comes ready to go with new sites. It comes with one semi-controversial choice and one very controversial choice.
The semi-controversial choice: it comes preconfigured with TailwindCSS. I neither love nor hate Tailwind. I chose it for this because it makes it very easy to just throw some shit together. It takes two seconds to pull it out if you don't like it.
The very controversial choice: it comes preconfigured with ReScript. I'll be talking about ReScript on an upcoming episode of Dead Code, but if you're not already familiar with it, here's what you need to know: It's the thing we should all be writing instead of TypeScript.
I think I've written a little about it in previous Skill Issues, but ReScript is basically OCaml with a better Syntax that compiles to JavaScript (and has an extremely good interop story). I don't burden clients with this technology because it's not used widely, but it rules and I use it on all my personal stuff.
Next Features
This weekend I'll probably add a few more features and cut a release. Here's the short list:
- There needs to be a better API for introspecting on pages.
- New sites should have a site map (part of the motivation for page introspection).
- I want new sites to come with a basic blog post implementation (with RSS feed) to serve as a reference for building out more elaborate content.
Ultimately, I think this thing is just shy of being ready to actually new up the projects for the Super Good and Jardo sites and get working on them. I'm going to hold off on a v1.0 release of Wytch until I ship the sites, though. I don't want to have to worry about breaking changes.
Master Boot Record
I've been on an MBR kick lately. Master Boot Record is an Italian music project that aims to create symphonic metal using only synthesizers. It's a ton of fun and the live shows are wild. They add live instrumentation to the synth tracks, creating something totally unique. I was fortunate enough to catch them when they came through Vancouver.
Here they are adapting e1m1 from the original Doom soundtrack.