Schemescape

Development log of a life-long coder

Designing md2blog 2.0

I really didn't want to do this. I probably shouldn't have done this. But I did it anyway.

I created yet another static site generator.

The recent past

After investigating a bunch of existing static site generators, I eventually settled on using Metalsmith (and various plugins) to build my static dev blog. I even went so far as to clean up my code in hopes of releasing a zero-config static dev blog generator called md2blog.

But in the end, it just didn't feel right to publish a tool on NPM with 18 direct dependencies and over 200 transitive dependencies (including 6 different file matching libraries). I'm personally concerned about the NPM ecosystem's outrageous dependency trees, and their security implications (Dependency Hell 2.0?), so I decided that I shouldn't be further contributing to the problem.

Enter Deno

Fortunately, as noted in my post about NPM, there's a relatively new JavaScript (and TypeScript) runtime with a security focus: Deno.

Deno doesn't magically make it 100% safe to download and run JavaScript code from anywhere, but it at least tries to provide a secure environment by sand boxing JavaScript programs (similar to what is done in a web browser) and only allowing certain operations if permissions are explicitly granted on the command line, e.g.:

$ deno run --allow-read=content,out --allow-write=out main.js

Additionally, Deno provides a standard library that has been audited by the Deno authors, so you no longer have to pull in modules from unknown contributors just for common tasks like, say, parsing YAML front matter.

Deno also has a focus on the full developer experience and includes facilities for testing, static analysis, dependency analysis, stand-alone executables, and more. Again, this means that you don't have to rely on tens or hundreds of NPM packages just to run some unit tests or publish a stand-alone tool. Oh, and Deno fully embraces await and async, so no more dealing with tedious error-first callback patterns!

Goodbye, Metalsmith

While Deno has some facilities for running Node/NPM modules, I decided that, in order to limit the number of dependencies I take on and to leverage async language features, I would essentially recreate Metalsmith for Deno. Fortunately, Metalsmith is so simple, my prototype was under 150 lines of code.

For now, I'm calling this module Goldsmith. Here's how Goldsmith differs from Metalsmith:

Plugins and dependencies

Given that most of the Metalsmith plugins I was using were trivially simple, I decided that I'd just rewrite the ones I needed from scratch in TypeScript.

Along the way, I made a few changes to further reduce the number of dependencies:

Current state of the tool

While none of the above libraries are fit for general consumption yet, the page you're reading was generated with my rewritten Deno-based tool. Other than cleaning up the code, adding tests, and releasing everything, the only functionality that is currently missing is:

  1. Command line configuration arguments
  2. Test web server with automatic reloading

The first one should be easy, and I think the second one shouldn't be too hard either (hopefully just a matter of injecting a script to connect to a WebSocket that pushes out reload requests based on Deno.watchFs()).

Update: Both of these are now implemented.

A parting note

So there you have it. Depending on how you count, this is either the 4th or 5th static site generator I've built. I like to hope this will be my last.