A shared layout

With Metalsmith in place, time to do a little more than just copying files around. Most the pages of the site will share a common layout, and it would be innefficient and error-prone to copy-paste it from file to file. Let's remediate to that and separate the layout from the content itself.

Wrapping the content in a common layout is a standard thing to do with static site generators, and when building websites in general. Metalsmith provides a ready made plugin for that, aptly named metalsmith-layouts,so let's bring it in.

Picking a templating language

Sharing a common layout will require the use of templates. And there are plenty of templating languages around. Each with their own syntax more or less close to HTML, each with their own API.

A key thing for me is that is allows to run arbitrary JavaScript code inside the template. As much as we want to keep business logic out of the templates, there's always some templating logic that will require a little more than an if or a loop. Maybe building a couple of HTML attributes from the template data. Having to edit a file miles away from the template itself gets in the way more than it helps.

This led to the choice of Pug for templating.

The setup

To get the layouts in place, we'll need the metalsmith-layouts plugin itself. Under the hood, it uses jstransformer, a library that standardises the API for calling the various existing template libraries. We'll need to install it too, along with the package for Pug, jstransformer-pug.

npm i metalsmith-layouts jstransformer jstransformer-pug

We can then add the plugin to Metalsmith in the src/index.js file. The plugin will need the name of a default template, so let's say site.pug.

/* ... */
const layouts = require('metalsmith-layouts')
/* ... */
  .destination('./site')
  .use(
    layouts({
      default: 'site.pug'
    })
  )
  .build(function(err) {
/* ... */

The layouts are looked up from the layouts folder, so let's create a layouts/site.pug file with some common parts:

<!doctype html>
html(lang="en")
  head
    meta(charset="UTF-8")
    meta(name="viewport", content="width=device-width, initial-scale=1.0")
    title Romaric Pascal
  body
    != contents

We'll quickly need to update it to make sure each page has a different title, but it'll wrap each piece of content in the same shell of HTML. To avoid injecting malicious tags, Pug escapes all the data it outputs. Handy when it comes from user input, but here it's our own content that we fully control. We can safely output it unescaped with != rather than =.

Having the layout in place now allows to reduce the files in the content folder to just the content bits. Say a src/index.html file like this:

<h1>It works!<h1>

Running node src/index.js, Metalsmith will combine it with the layout to output the following as site/index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Romaric Pascal</title>
  </head>
  <body>
    <h1>It works</h1>
  </body>
</html>

There we go! We can edit a unique layout file to affect all the pages of the site. That's already better than copy-pasting. Now lets go further and shift to having the content written in Markdown, rather than plain HTML. It'll be much easier to edit, but it'll be for the next article.