Choosing a Static Site Generator

For probably the past three or four years, my icon gallery sites (iosicongallery, macosicongallery, and watchosicongallery) have been powered by Jekyll. Each icon on the site is a “post” in Jekyll without any body content, i.e.

---
title: "Facebook"
slug: facebook
date: 2018-04-24
# more stuff here
---

Each site had its own Github repo consisting of the posts and images for each site’s content. In addition, each repo contained a git submodule which constituted the theme for each site (i.e. shared code, templates, styles, images, etc.) The site was served by Github pages, so anytime I made an update to one of the sites’ repos, Github would handle building and deploying my site.

This has all worked pretty well over the past few years, but a few drawbacks of this approach have increasingly reared their head:

I’d been thinking about switching over to Netlify as my host for some time, which would free me from the tyranny of only a single choice when it comes to a static site generator. So I decided to finally take the plunge and get a new static site generator and hosting solution for my icon galleries.

Choosing a Static Site Generator

As you’re probably aware, your options for a static site generator these days are basically like your options at a buffet: unlimited. I had my finger on the pulse of what was happening with modern static site generators, but I checked out StaticGen to refresh my memory. At the time of this writing, the top five static site generators on that site were:

  1. Jekyll
  2. Next
  3. Hugo
  4. Gatsby
  5. Hexo

I wanted a static site generator written in node, so that ruled out Jekyll (Ruby) and Hugo (GO). But the other three were definite options. I spent some time browsing the documentation of a variety of static site generator projects, taking into consideration popularity, project activity, templating options, clarity of written documentation, and underlying ideas of the technology. After sifting through quite a few JavaScript-based options, I whittled my choices down to the following four options:

  1. Next
  2. Gatsby
  3. Hexo
  4. Metalsmith

Next

After digging through their docs and trying some of their example code around generating a static site with my own content, I eventually gave up because I couldn’t even get the thing to work. Maybe that’s because I’m just not that good with computers and tooling, but I’m going to chalk it up to the fact that using this tool as a static site generator is not the intended, primary usage. It’s like a “hey you can do that too!” but the primary use cases and documentation focus on it being a framework for server-rendered applications. In fact, if you Google “nextjs static site generator” the first result drives you to a project called nextein which claims to be “a static site generator based in Next.js”.

Gatsby

I really wanted to use Gatsby. I wanted to write my templates in JSX. And Gatsby has some much attention these days, I knew finding answers to questions would be relatively simple. The project has lots of activity and a strong developer base around it. All things I wanted from my new static site generator.

However, the one thing that really ended up being a deal-breaker for me was that Gatsby felt too sophisticated for my use case. One of the tests I had in my mind while evaluating these tools was that I would browse the documentation and if I couldn’t understand how to get started and feel excited about starting within five to ten minutes of reading the documentation, I gave up. I gave Gatsby even more time than that because lots of people were vouching for it. But at the end of the day, it felt like too much complexity for what I was trying to do. Too many variable web technologies that I was afraid could change in six months and I’d be playing catch-up constantly. I wanted something like what Jekyll had been: write my site and leave the code for years with minimal involvement. I didn’t feel like that would be possible with Gatsby (granted there’s probably a contradiction in there, that I wanted React but also code I wouldn’t have to touch and maybe you’re right, but having React vs. having React and Webpack and GraphQl and CSS-in-JSS tools and others felt like a bit much.) In the end, I could never muster up the courage to even try standing up a prototype. For me, there was just too much going on. I wanted something more like “here’s my markdown files, here’s my templates, go!”

Hexo

I really liked Hexo. After about three minutes of reading the docs, I had a clear picture of how to get started. I even got my site up and running in a crude fashion using Hexo’s framework and it was insanely fast. Jekyll was building my site in roughly 60 seconds while Hexo could do it in about 10. Plus the development build was incremental and also way faster than Jekyll’s.

For a while I thought I might even end up with Hexo. But the more and more I refined my prototype towards a production-ready product, the more and more I found myself struggling to find answers to questions. Anytime I Google’d an error or question, I’d find some comparable stack trace in a foreign language. In some ways, it almost felt like a bait and switch: Hexo’s docs were great at the introduction, but the more you got into actual implementation, the more you found how incomplete the docs were (or unclear, as though they were written by someone whose first language wasn’t English). So essentially I found myself having the same problem I outlined above with Jekyll, except instead of the code being in a foreign programming language, the ecosystem around the code was primarily in a foreign human language. I continued to build my site on top of it, but the further I got, the more I felt like this wasn’t going to work.

Fortunately, Hexo and I were still dating and we hadn’t gotten married, so I started looking around for other options.

Metalsmith

I had actually been introduced to Metalsmith on a prior project a few years back by my friend damassi, but my JS skills back then weren’t polished enough to really understand it. When I dug through Metalsmith’s docs, what really struck me about the framework wasn’t so much what technologies they were using under the hood (or rather which ones they weren’t using, no React, no Webpack, no Babel, etc) but the ideas behind the code. Metalsmith is built on the idea that (their take on) a static site generator operates on this simple premise:

  1. Take a directory of files
  2. Manipulate those files in a variety of ways
  3. Write the manipulated information to disk as a website.

Metalsmith touts itself as a “pluggable static site generator”. The core library is merely an abstraction for manipulating a directory of files. Everything else is done by plugins. The idea behind what Metalsmith was doing really attracted me, as code and technologies change but ideas persist. However, when trying to implement my site on top of Metalsmith I kept running into problems. In fact, I ran into problems enough times that I gave up. It wasn’t as convenient as Hexo which prescribed I do things a certain way. Metalsmith was more open-ended and (at first) I didn’t like that.

So I ended up doing a dance between Metalsmith and Hexo. When I didn’t like Metalsmith, I’d say “Ok I’m building this in Hexo”. Then when I got to the point that I didn’t like Hexo, I’d say “Ok, nevermind, I’m going to build this in Metalsmith”. Eventually I got so unsatisfied with both that I just told myself that I would build my own static site generator.

Screenshot of tweet

However, I eventually found this blog post which is what gave me the “ah-ha!” moment I needed to understand how Metalsmith worked. In the back of my mind, a line from Metalsmith’s docs kept coming into my mind which basically said “once you get how Metalsmith is working under the hood and what’s happening, it all clicks.” I finally had that moment and when it clicked, I realized Metalsmith was going to be my choice.

In the end, what I really liked about going with Metalsmith is that I didn’t feel tied to any particular technology. Sure, there was the core Metalsmith, but outside of that, everything I wanted to do with my site could be done by writing my own plugins. It felt like I was just writing JavaScript for node. I wasn’t writing Hexo code, or Gatsby code, or Next code. And because it was node, so “close to the metal”, I could do whatever I wanted in generating my site in terms of code, layout, templating, project structure, etc.

To clarify that point even more, what I really liked about Metalsmith is that the core idea of the static site generator was really simple once I understood it. With Hexo, for example, it always felt like “ok, I have to write a function in just such a way, then put it in a certain folder, then run a certain command and only then will Hexo do what I want”. It felt like writing Hexo-specific JavaScript. Whereas with Metalsmith, once I understood how the core worked, I was just writing JavaScript like I would for any node-based application.

I’ll grant that I’m not doing a good job of explaining this very well. Part of my enthusiasm for Metalsmith was just a feeling. A feeling that I get after writing JavaScript for other frameworks and projects. A feeling I liked, not just in the here-and-now, but for future Jim who will have to support the code I write in the here-and-now. And future Jim was ok with it.

Don’t get me wrong, metalsmith has its drawbacks. But at the end of the day, the ideas behind the code rather than the particular technologies behind the code were what won me over.

Example

Here’s an example of what I’m talking about.

So for my site I had a directory of .md files which represented each icon as a “post”. I had a separate directory of images which served as the source for the actual icon image files. In Jekyll, that was just a static directory that got copied over because I couldn’t hook into the build process. So my permalinks to a post might be /icons/:id/ where my index.html file was served, but the actual source for the icon <img> would be in whatever directory I had them in in my repo, so in the production site they’d be referenced at something like /img/src/:id since Jekyll was just doing a straight copy of files and folders.

What was really cool about Metalsmith is that it allowed me to hook into node in the build process and do whatever I wanted. So when Metalsmith was building each post, it would look for my source icon images and copy them over to the build directory in the same place where it was putting the index.html file for the icon’s post. This allowed me to build each site in a way such that I could leverage my site’s URLs as an interface for getting icons, i.e. /icons/:id/ for the HTML representation of the icon and /icons/:id/:size.png for the actual icon (i.e. /icons/facebook/512.png would give me facebook’s 512px app icon).

This was all possible because Metalsmith is just a series of transformations on your site’s content (which you write in JavaScript for node).

Conclusion

I ended up going with Metalsmith for static site generation and Netlify for hosting and I’ve been happy for the few weeks I’ve had things this way. Granted, I could totally regret this decision in a few years months weeks, but I’m happy now. And when it comes to personal projects, that’s all that really matters.