Asset Manifests with Swig Templates

I’m still using the Swig templating engine for my Node/Express apps and recently decided to streamline my asset caching process. I wanted a simple way to insert hashed assets into my templates but everything that Google came up with seemed a little too complicated. So I wrote a quick custom Swig tag to read from an asset manifest (in my case public/assets.json generated by the Webpack Manifest Plugin):

let assets = require('../../public/assets.json');

module.exports = function (swig) {
  swig.setTag('asset', _parse, _compile, false, true);
};

let _parse = function (str, line, parser) {
  parser.on('*', function (token) {
    let match = token.match.match(/^["'](.*?)["']$/);
    let assetPath = match ? match[1] : null;

    if (assetPath) {
      let asset = assets[assetPath] || assetPath;
      this.out.push(asset);
    }
  });

  return true;
};

let _compile = function (compiler, args) {
  if (!args || !args[0]) {
    throw new Error('The asset tag expects a filename as a string');
  }

  let assetPath = args[0].startsWith('/') ? args[0] : '/' + args[0];
  return `_output +="${assetPath}";`;
};

(GitHub Gist)

I keep this file in an app/helpers directory and in app.js my views are set up with the lines:

require('./app/helpers/assets')(swig);
app.engine('html', swig.renderFile);
app.set('view engine', 'html');

After that stylesheets or JavaScript can be added to any template using the unhashed name like so:

<script src="{% asset 'main.js' %}"></script>
<link rel="stylesheet" href="{% asset 'main.css' %}" />

Comments