DEV Community

loading...
Cover image for Properly precompile Handlebars templates and partials with Gulp

Properly precompile Handlebars templates and partials with Gulp

Jonatas de Moraes Junior
Love to learn, love to teach. And above all, love to question.
・2 min read

Read in portuguese: here

If you are using Handlebars as your web front-end's template engine, it is generally a good idea to send precompiled templates to the browser instead of leaving to the the client the job of compiling every single template it requires.

I'll present here a Gulp script I've been using for this task for some time now. It will seek any .hbs files in your src folder, precompile it, and output a single templates.js file on your dist/js folder. It will also pick any file whose filename starts with _ and set it up as a handlebars partial, so it can be included in other templates (just remember to omit the _ character when including, eg, _myInclude.hbs becomes {{>myInclude}}).

In your javascript code, you will get the template like this:
const stringTemplate = Hbs['your_template_name_here'];.

Without futher delay, here is the code:

const { src, dest, series } = require('gulp');
const concat = require('gulp-concat');
const declare = require('gulp-declare');
const del = require('del');
const handlebars = require('gulp-handlebars');
const merge = require('merge2');
const path = require('path');
const rename = require('gulp-rename');
const wrap = require('gulp-wrap');

const target = 'dist/js';

function clean() {
  return del('dist');
}

function templates() {
  return src('src/**/*.hbs')
  .pipe(rename((path) => {
    if (path.basename.startsWith('_')) {
      path.basename = path.basename.substring(1);
    }
  }))
  .pipe(handlebars())
  .pipe(wrap('Handlebars.template(<%= contents %>)'))
  .pipe(declare({
    namespace: 'Hbs',
    noRedeclare: true,
  }));
}

function partials() {
  return src('src/**/_*.hbs')
  .pipe(handlebars())
  .pipe(wrap('Handlebars.registerPartial(<%= processPartialName(file.relative) %>, Hbs[<%= processPartialName(file.relative) %>]);', {}, {
    imports: {
      processPartialName: function(fileName) {
        return JSON.stringify(path.basename(fileName, '.js').substring(1));
      }
    }
  }));
}

function hbs() {
  return merge(templates(), partials())
    .pipe(concat('templates.js'))
    .pipe(dest(target));
}

exports.default = series(
  clean,
  hbs,
);
Enter fullscreen mode Exit fullscreen mode

The big catch here are the partials. For Handlebars, any template can be identified as a partial, but before you can do that, you have to create the template first. So, what this script does is to precompile every template (including the partials) and then, for every file that starts with _, set it up as a partial.

Of course, if you are using Gulp to build your application, you will not use a variety of gulp files, so the best thing to do here is to pick up some of those methods and add them to your own gulpfile. One thing that I do in my gulpfiles is to do not output the precompiled templates to a file, but rather concatenate its output with the rest of the javascript I generate and, if this is a production build, minify it.

It took me a while to figure all this out, so I hope this helps speeding up your journey of getting away from mainstream frameworks. =)

Discussion (0)

Forem Open with the Forem app