Hello, World... (Again)

I've been considering a new site for a while so that I could share a bit of writing occasionally but there were always two main things that held me back.

Firstly, Archive.org will remember everything I post for the rest of time whether I like it or not. I've taken time to think and I've got a good idea about what lines I'm willing to cross and also what content I'd like to share in general. I have multiple projects in mind that will probably be worth writing about.

The other thing that held me back was that I couldn't find a platform or framework I actually liked for a personal site. I didn't want to start writing content only to then be frustrated by the tools.

Choosing a platform

If you don't have a team of non-technical users then features such as editors and dashboards are completely unnecessary and are a really bad deal. Dynamic features present a large attack surface both in terms of the application itself and also the system it is hosted on. You also take on considerable maintenance obligations and incur monthly costs... And if it fails you look like an idiot.

Another Django based site isn't an option.
Wordpress? Absolutely not.
HEY World? Neat, but too simplistic and not self hosted.

Many static site frameworks still come with a whole lot of baggage, though generally half as much as dynamic platforms. In the end you have to understand and apply someone else's framework and workflow to your project. Copious dependencies still might need to be installed on your system just to write a new blog entry once every few months. Screw that.

Security

Lately I've become very concerned about security. There have been multiple severe NPM and PyPI supply chain attacks (among others) this year. Security needs to be treated as a first class feature now that the cost of creating exploits is lower than ever and the need to pare down third-party dependencies - even for tools running locally - is clear.

With AI, it's now often feasible to replace a third-party dependency with a smaller, project-specific implementation inside your own codebase. You can strip away the liability the third-party poses and also the liability of any bundled features that you don't use or want. On the other hand relying on AI to generate replacements for third-party dependencies comes with significant downsides too; the generated code is now your responsibility and you may not have the domain expertise to ensure correctness, security, etc.

The wish-list

Over the course of two days I meditated on what my ideal static site generator might look like and produced a wish list:

  1. No baggage - I don’t mind carrying around content and assets in backups or on my laptop, but Python and Node.js environments tend to leave a mess behind. Virtual environments, package caches, node_modules directories, toolchains that drift out of date. It all adds up.

    When I come back a year later, or switch to a new device, I don’t want to reinstall half the internet just to get a blog building again. I want something that works without dependency hell or supply chain anxiety.

  2. No dependencies - or at least as close as possible. Pulling them from NPM, PyPI, or crates.io every time you want to work on a website or on the site generator is out.

  3. Zero friction when adding content - I want to put files in a directory structure that reflects my URL scheme, run a build command and run a deploy command.

  4. Simple as possible - A minimal templating system. No databases or state. No plugins. No configuration files. Nuxt Content style front-matter for directives and metadata can be defined at the top of any markdown file. If I go away and come back a year later I shouldn't be surprised by how the system works or forced to rack my memory for basic usage details.

  5. We need to build, but we don't need a whole freakin' build chain - No kludge of tools, multi-pass compilation or directed-graph craziness.

Rather than pin my hopes on someone else's solution, I decided to build my own static site generator.

Did I hand code it? Nope. I fired up Claude - laid out my vision in plain language, discussed some implementation details and let it rip. It did a surprisingly good job.

After the initial prototype I decided to invest in additional features. Adding metadata to my pages to help crawlers and social media integration was trivial. Adding an Atom feed was easy and helped round out the project. The old habit of mapping every feature to a third-party library was easy to break.

Gosite

The implementation is easiest to summarise in a few points:

  • Written in Go because it produces a single binary easily, has a strong standard library, avoids extra build tooling and is much more performant than scripted langugages.
  • Templating from the Go standard library. Perfectly adequate.
  • goldmark for markdown. Despite being a third-party dependency I feel it is well worth it and likely trustworthy. To reduce risk I used go mod vendor to bring it into the project codebase. All content being processed is local and presumably trustworthy so it might never have to be updated.
  • tailwind-cli as an optional dependency. This is a standalone binary. I really prefer to use Tailwind over raw CSS. The generated output only includes relevant tailwind classes and is also minified.
  • Task as another optional dependency. It's trivial to run gosite directly (e.g. simply "gosite build") but it's nice to have a Taskfile which wraps up all your common commands and injects environment variables from a .env file. I also use it to run tailwind-cli automatically. Once you decide how you want to deploy just extend the Taskfile. You definitely could use a Makefile to do all these things, but you know... Current year.
  • Front-matter is in YAML key-value style but no third-party YAML dependency is used. Simple string parsing does the trick.
  • The gosite and tailwind-cli binaries sit in the site project directory. There isn't a Python virtual environment or node_modules directory in sight. It's blissful.

In the near future I may make the source for Gosite public. There are many static website generators but this one is mine.

This Site

Obviously what you see here is the Gosite output.

The look and feel is recycled from my last business-card style website because after browsing other portfolio and blog websites I couldn't find themes and trends that felt right. I'm still in disbelief that I'd actually managed to create something with aesthetic value all by myself! Visuals have always been my weakness.

I've held firm to a "no JavaScript" approach and I'm quite happy with the results. It's a lot easier to make nice sites with modern CSS features. A modern SPA-like experience with transitions between separate HTML pages can be done without JavaScript! What a time to be alive! The reduced size and load time is also very satisfying especially combined with some browser preloading.

When you go to a minimal website that has nice typography and a distinct lack of chrome you know you're about to get an education even if the content is a collection of rants by an aging sysadmin that people frequently mistake for a homeless person. I wanted to bring a little of that energy to my site.

There's no comment section because frankly I don't need one. People can comment on social media or email me. Comment sections on blogs mostly act as a spam archive these days.

There is dark-mode support but it relies on your OS/browser using prefers-color-scheme to trigger the dark mode CSS. Adding a dark-mode toggle would definitely require JavaScript and that's where I draw the line.