Software! Math! Data! The blog of R. Sean Bowman
The blog of R. Sean Bowman
March 18 2016

I switched my site to use metalsmith, a node based static site generator. This is the obligatory post about how, why, tips and tricks, and so on.

My old blog used middleman, which is a very nice static site generator. It gives you lots of control over how your site is set up, including which templating engine you use, what plugins you install or write, and so on. But it’s written in Ruby, and that started to get to me. I worked on another static site using middleman that had several custom plugins, and those were not fun to write or maintain. It was never clear how they interacted with the internals of middleman, which are not very clearly documented anyway.

The Ruby attitude to plugins and extensibility in general seems to involve lots of monkey patching (adding or changing methods of existing classes or even objects at runtime) and magic that I am wary of. Don’t get me wrong – Ruby can be a beautiful language, particularly expressive with its blocks acting like higher order functions. I enjoyed writing in Ruby, but I did not like interfacing with other code. Or maybe I’m just making that up to justify the change. Who knows.

In any case, my blog, this blog worked file, and I didn’t see much reason to change until – again – I was working on another site and experimenting with alternative generators. I found metalsmith It’s not perfect, but I’m having fun with it right now.

How it works, roughly

Metalsmith is very lightweight: the whole thing (right now) is about 350 lines of javascript. I’m not one who cares too much about the size of this or that, or how many lines of code, or blah blah blah, but clearly this is a system that we have some hope of understanding. In particular, understanding how to interface with.

And interfacing with metalsmith is important, because in metalsmith everything is a plugin. I mean, you can’t get that far with 350 lines of code, right? So the idea is that metalsmith provides a pipeline for a set of source files to be acted upon and written to a destination directory. The source files are your blog posts, pages, templates, css, javascript, images, and whatever else your website is comprised of, and the output is a static website ready to be uploaded to your favorite host.

But in fact, there’s nothing about metalsmith that makes it a HTML website generator. It could just as easily take a directory containing content files, templates, and other stuff, and write a directory containing an ebook, or technical documentation, or whatever you can think of. I haven’t done this yet, but the idea is interesting.

Plugins & Customization

I’ll let you read about the basics of metalsmith, getting it set up, and so forth, but I do want to talk about some customizations I made. You can check out the code for this website, the site you’re reading right now. I’ve left out most of the content as I tend to keep lots of drafts laying around for a long time, but the code that make it work is all there.

To create a metalsmith blog, you generally start by selecting some plugins to assemble in to a pipeline. Lots of these are no brainers: the plugins from Segment, who developed metalsmith, are quite good. These are things like metalsmith-permalinks for customizable permalinks and nice urls and metalsmith-collections for grouping together posts in order to act upon the group later.

Although there are lots of nice plugins out there, chances are that if you have a specific requirement for your site, you’ll need to write at least one of your own. In my case, the old middleman site used urls based on the file names, whereas the default metalsmith permalinks options don’t include that. No big deal though: the things flowing through the metalsmith pipeline are not really files, they’re big blobs of data and metadata, including the file contents and path. I use this plugin to grab the base name of the file, the name without any path information and without an extension:

function basename() {
  return function(files) {
    Object.keys(files).forEach(file => {
      const parts = path.parse(file);
      files[file].basename = parts.name;
    });
  };
}

Easy as dirt. This function just returns a function with a standard signature: files is an object whose keys are file paths and values are the data and metadata associated with the file. We go through each file and use the path module that is part of node to obtain the base name of the file, adding it to the files metadata.

Note that many (most?) plugins use an older syntax where the signature for the returned function takes three arguments: files, a metalsmith object, and a callback usually called done that indicates that the plugin has finished or there has been an error the plugin wants to propagate.

Things working together in harmony

What’s the use of this? Later in the pipeline I use the permalinks plugin linked to above, like this

// big chain of "use" methods
.use(permalinks({
  pattern: ":basename",
  relative: false,
  linksets: [{
    match: { collection: "posts" },
    pattern: "blog/:basename"
  }]
}))
// chains to another "use" method, etc.

The basename property we set previously is now available to the permalinks plugin, which can now generate permalinks that look exactly like the ones on my old blog. No need for redirects and the web is saved from link rot.

Templating and tricks

In metalsmith, templating is split into two parts. There’s metalsmith-layouts for applying layouts to your source files. This takes a markdown post, for example, and wraps it in a web page with header, footer, sidebar, and whatever else you like.

There’s also metalsmith-in-place, which I didn’t understand for the longest time. This is quite a powerful plugin, though, if you know what you’re doing: it allows you to render templates in your source files. It uses consolidate.js to abstract the particular templating engine away, so you can use your choice of several popular ones; I’ll use handlebars since that’s the one I use.

There are lots of things you can do with metalsmith-in-place, but here’s how I use it. In my blog posts, which are markdown files, I occasionally want to do something like include a figure. My blog uses bootstrap, so the figure needs to have some classes I can never remember, blah blah blah, it’s a pain. So, instead of writing out an HTML img tag, I use a handlebars helper, like this:

blah blah, here's a picture of me at the beach

{{{ include_image "myimage.png" "Me at the beach or something" }}}

and other stuff, etc., etc.

In my pipeline, I have metalsmith-in-place using handlebars, and I’ve registered a helper for include_image like this:

const handlebars = require("handlebars");

handlebars.registerHelper("include_image", (name, alt_text) => {
  return ['<img src="/images/"', name, '" alt="',
          alt_text, '">'].join("");
});

At the appropriate place in the pipeline, the handlebars tag in the markdown file is converted to an image tag by the helper, it becomes an HTML fragment, and then it’s rendered to a page by the layout plugin. Nifty!

Conclusion

I’ve said it before and I’ll say it again: javascript is not my favorite language to program in. That’s a strike against metalsmith. Another is that it does not support incremental compilation. That is, if you change one word of one of your posts and run metalsmith, your entire site gets regenerated. It’s not a big deal for me – I suspect this site could get pretty huge without it begin a problem. But it might be a bigger deal for other folks.

Two more semi-related problems with metalsmith is that the documentation is lacking and you need to be a pretty hardcore programmer to use the tool, moreso than other popular generators like middleman, jekyll, or hugo. You’ll almost certainly need to write a plugin if you have any nontrivial needs (or else let the existing plugins dictate the design of your site – no fun!), and you need some context to do that. That context mostly comes from other blog posts and a little documentation on the metalsmith website. It’s true that many static site generators are geared towards developers, but I think this is even more the case with metalsmith.

Even with the strikes against it I must admit, I enjoy using metalsmith. I feel like I can understand pretty much every part of what it’s doing, and when I need to extend it, there’s no problem. Plugins are easy to write. I like the way my site turned out, and the development and writing process seems to work well. I’m happy and would definitely recommend having a look if you’re searching for a static site/blog/whatever generator.

Approx. 1463 words, plus code