A long time ago, in the heady days before Medium, I had an opinion about CSS that I wanted to put on the internet, so I knocked out a quick, hot pink static blog with the excellent Middleman.

Fast-forward a couple of years and whatever blessed combination of versions of Ruby, Middleman and its dependencies I'd built the site with was lost to the mists of time. I'd hacked up the source too much to simply upgrade everything.

bundle exec middleman was dead and I was too lazy to fix it.

Luckily, I've been travelling around the world for the past 10 months, which means I've had the occasional slice of bus, train, airport or collectivo time to build this new blog!

Under the hood

I had a few requirements.

I tried out a few of the popular static site generators including Middleman (again), Gatsby, Hexo, Harp.js, Wintersmith and Metalsmith. Ultimately none of them were a simple npm install yarn install away from doing everything I wanted, and I didn't want to customise them so much that I wouldn't be able to update dependencies easily (i.e., exactly the problem I made for myself last time).

Here's what I ended up with:


Metalsmith bills itself as "an extremely simple, pluggable static site generator" which is a solid description. Everything is a plugin - all the core metalsmith package lets you do is:

  1. Read all the files in a source directory.
  2. Invoke a series of plugins that manipulate the files.
  3. Write the results to a destination directory!

I couldn't find Metalsmith plugins to satisfy all of my requirements, but I was able to generate static HTML with the URL structure I wanted, from Markdown + Front Matter source files and simple EJS templates, exactly like I wanted, as well as an RSS feed.

I'm very OK with this being all that Metalsmith does. It does these things very well and the scope of its responsibilities is small enough that it all fits in my head. If it also handled CSS and assets and a dev server and deployments (which it probably can with enough plugins), it might feel like more of a black box.

As mentioned, you need a plugin to do literally anything with Metalsmith. I used...

Why EJS?

Everybody should use React for everything all the time, right?

Well, no. I love component-based architecture and hot reloading and new ways of doing CSS - they genuinely make life easier when the project and team size warrant it.

This site has 2 pages (home & posts) and 1 maintainer (me). A Facebook-sized project this is not.

I prefer EJS (and other embedded language templates like ERB or even plain old PHP) over things like Jade Pug, HAML, Handlebars or Liquid for the simple reason that it's the same plain HTML I'll be inspecting in Chrome plus the power of a real programming language I already know - no converting HAML to HTML in my head and no need to learn a template-specific if statement.


I decided to see how far I could get with a single plain CSS file to go along with my two HTML templates and quickly discovered that I missed a few things from my usual CSS workflow:

I was already including PostCSS for Autoprefixer, so I had a look around for a few extra plugins and found:

Gulp asset pipeline

I needed file watching, image optimisation, asset revving and multiple PostCSS steps. I'm yet to find a neater option for all of that than Gulp.

It's easy to fall into the trap of using Gulp (with a bunch obscure, unmaintained Gulp plugins) for everything just because it's useful for some things. I really wanted to avoid that "one enormous Gulpfile to rule them all" approach.

I have simple, standalone Gulp tasks for the following:

Dev server

The dev server is really simple. I just generate the site into the same public folder I deploy from (minus image optimisation and asset revving), watch some files and serve everything with http-server.

It's all tied together with node-foreman. Here's my Procfile:

metalsmith: gulp metalsmith-watch
stylesheets: gulp stylesheets-watch
images: gulp images-watch
http-server: http-server -p 4000 -c-1

The -c-1 flag for http-server just disables caching.

Deploying and hosting

After generating, the site is deployed to GitHub Pages. There are a bunch of tools that will take your public folder, switch to a gh-pages branch, commit and push. This sweet, adequately-named bash script called git-directory-deploy does the job for me.

There's a downside to just deploying to GitHub Pages - the cache headers they set on static assets:


Static assets will only cached by browsers for 10 minutes.

It's a reasonable default for the average GitHub Pages website - if you push a new version of an asset to GitHub without renaming it, you probably want it to update soon afterwards on your site (or sooner with a hard refresh).

However I've got these neat unique revved asset file names that mean assets can be cached forever. I'll never "update" an image or CSS file; I'll always deploy a brand new file with a brand new file name and update any references in the HTML.

So I put free CloudFlare in front of GitHub Pages (roughly like this). This gives me a few things you can't get with plain GitHub Pages:

This setup means my website is fast. Fast websites are good.

No client side JavaScript

With the exception of Google Analytics and Disqus embed snippets, there's no client side JS on this site (yet).

It's a little blog, so it doesn't really need any JS, but something I looked at was Turbolinks-style no-reload page transitions. Gatsby gives you this for free via react-router.

However after a year of travelling and using patchy internet connections, I'm convinced that these page transitions are a poor default choice for most sites.

The browser's native spinner, loading bar and error screens are incredibly useful and consistent feedback mechanisms for users. When you toss them out in favour of a bespoke JavaScript implementation that probably doesn't cover every base that browsers cover, you make the experience worse for users on even mediocre connections.

I've got a larger blog post/rant on this very topic in the works. Now that I have a functioning blog again I have somewhere to post it, so watch this space!

Or be cool and subscribe to this fancy RSS feed.