No gems (one asterisk)
./blog.sh needs no gems. Here's the one asterisk on that sentence, because a claim without its exception isn't worth much.
The claim first: zero gems, zero npm packages, no Bundler, no lockfile, no node_modules folder quietly gaining weight in the dark. Ruby 2.7 or newer and bash. Clone it and it runs.
The asterisk, up front
Two optional sidebar widgets — Pixelfed and generic RSS — parse XML with rexml. That's a default gem: it ships bundled with every normal Ruby installation, so for most people the claim holds as written. But some Linux distributions split Ruby into packages and put the default gems in a separate one.
So: if you enable those two widgets on a distro-packaged Ruby and the build complains about rexml, you're the asterisk. Two ways out — install your distro's ruby-rexml-ish package, or gem install rexml. Either way it's one package, once, and only if you use those widgets at all.
That's the entire dependency story. I'd rather write it out than round it down to zero and wait for someone's build to disagree.
What a real zero buys you
No network dependencies at build time means the entire site builds offline. On a plane, on a train, on a server that firewalled itself into a corner — ruby build/build_blog.rb neither knows nor cares.
And the output is as boring as the input. Measured on this site, today, fourteen posts:
| Measured on this site | Value |
|---|---|
| Full build, cold | 1.9 s |
| Full build, warm (only changed files written) | 0.9 s |
| Homepage HTML | 54 kB |
| All CSS | 24 kB |
| All JavaScript | 23 kB — 555 lines across 8 files |
| Requests to third-party domains | 1* |
That JavaScript is the complete inventory: theme toggle, lightbox, client-side search, the comments loader, sidebar widgets, mobile nav, scroll-to-top, and a shared utility file. No framework is hiding under any of them.
And yes, a second asterisk snuck into the table, same policy as the first: the one third-party request is my own self-hosted Umami analytics, on another domain of mine, added through the config. The engine itself ships exactly zero — no fonts CDN, no tracker, no embed phoning home. Turn the analytics line off in site.yml and the number is a structural 0.
Why bother
Because every dependency is a small standing appointment with the future. Some Tuesday it needs updating, audits, replacing, or it deprecates the one function you used. A stdlib-only tool skips those appointments — the price is writing a bit more code yourself, and for a blog engine that price turned out to be surprisingly low.
A zero with its exception written down is more useful than a zero without one. If you trust the asterisk, you can trust the rest of the table.

Comments