rollup-plugin-handlebars-plus
Rollup plugin to precompile and resolve Handlebars templates.
Features:
- Import Handlebars templates as ES6 modules
- Support for Handlebars helpers and partials
- Precompiles templates so your application only needs the Handlebars runtime
- Handlebars runtime included
- Optional rendering to jQuery collections vs. raw strings
Installation
npm install rollup-plugin-handlebars-plus
or
npm install rollup-plugin-handlebars-plus --save
To use the plugin's copy of the Handlebars runtime, you'll also need to do:
npm install rollup-plugin-node-resolve rollup-plugin-commonjs
or
npm install rollup-plugin-node-resolve rollup-plugin-commonjs --save
See here for more information.
Usage
var rollup = require('rollup');
var handlebars = require('rollup-plugin-handlebars-plus');
var rootImport = require('rollup-plugin-root-import');
var partialRoots = [`${__dirname}/src/client/js/views/`, `${__dirname}/src/common/views/`];
rollup({
entry: 'main.js',
plugins: [
rootImport({
root: partialRoots,
}),
handlebars({
handlebars: {
id: 'handlebars',
module: require('handlebars'),
options: {
sourceMap: true,
},
},
helpers: ['/utils/HandlebarsHelpers.js'],
helpersPureInitialize: true,
templateExtension: '.html',
isPartial: (name) => name.startsWith('_'),
partialRoot: partialRoots,
jquery: 'jquery',
}),
],
});
lets you do this:
{{! src/client/js/views/_messageBody.html }}
<p>{{message}}</p>
{{! src/client/js/views/message.html }}
<div>{{> _messageBody }}</div>
import $ from 'jquery';
import MessageTemplate from 'message.html';
$('body').append(MessageTemplate({ message: 'Hello world!' }));
Helpers
You can load Handlebars helpers using the helpers
option, whose value is the ID(s) of modules to
import before every template. They should export as default
a function that accepts the Handlebars
runtime as argument, letting them register helpers. Each such export will only be invoked once.
var rollup = require('rollup');
var handlebars = require('rollup-plugin-handlebars-plus');
rollup({
entry: 'main.js',
plugins: [
handlebars({
helpers: ['/utils/HandlebarsHelpers.js'],
}),
],
});
export default function (Handlebars) {
Handlebars.registerHelper('encodeURIComponent', function (text) {
return new Handlebars.SafeString(encodeURIComponent(text));
});
}
{{! dashboardLink.hbs }}
<a href="https://app.mixmax.com/dashboard/live?user={{encodeURIComponent email}}">Dashboard</a>
import DashboardLinkTemplate from './dashboardLink.hbs';
console.log(DashboardLinkTemplate({ email: 'jeff@mixmax.com' }));
Handlebars
This plugin produces precompiled templates, which
then need to be rendered by the Handlebars runtime. You can either bundle the runtime yourself
and provide its module ID to this plugin using the handlebars.id
option, or you can let the
plugin bundle its own copy of the runtime.
The advantage of the latter is that compatibility is
guaranteed between the compiler and the runtime (see #6
here).
The tradeoff is that the plugin's copy of the runtime is a CJS module, so to load such you'll also
need to install rollup-plugin-node-resolve
and rollup-plugin-commonjs
:
var rollup = require('rollup');
var nodeResolve = require('rollup-plugin-node-resolve');
var commonjs = require('rollup-plugin-commonjs');
var handlebars = require('rollup-plugin-handlebars-plus');
rollup({
entry: 'main.js',
plugins: [
nodeResolve(),
commonjs({
include: 'node_modules/**',
}),
handlebars(),
],
});
In case you need the default runtime ID, it's available as handlebars.runtimeId
. This might be
useful if you want to import the runtime for use by templates precompiled by something other than
this plugin. In that case, you'll have to make sure that the other compiler's version is compatible
with this runtime.
jQuery
At Mixmax we often find it convenient to render templates to jQuery collections
rather than to raw strings. This lets us immediately manipulate the template as a DOM element, either
by passing it to an API that expects such like
Backbone.View#setElement:
import Backbone from 'backbone';
import Template from './index.html';
var MyView = Backbone.View.extend({
render() {
this.setElement(Template());
},
});
or by customizing the template using jQuery's APIs:
import $ from 'jquery';
import TooltipTemplate from './popdown.html';
var tooltip = TooltipTemplate();
tooltip.css({
left: 50,
top: 100,
});
$('body').append(tooltip);
What makes this possible is providing the module ID of jQuery (that you've bundled separately) to
this plugin, using the jquery
option:
var rollup = require('rollup');
var handlebars = require('rollup-plugin-handlebars-plus');
rollup({
entry: 'main.js',
plugins: [
handlebars({
jquery: 'jquery',
}),
],
});
Curious about how to ID jQuery when it's a global i.e. you're not bundling it?
Here's a Gist for that.
In case you want to render to a string even when using this option, all precompiled template functions
have the signature (data, options, asString)
so you can do:
import Template from './index.html';
console.log(Template({}, {}, true));
Contributing
We welcome pull requests! Please lint your code using the JSHint configuration in this project.
Credits
Created by Eli Skeggs and Jeff Wear.
Prior art: https://github.com/jibhaine/rollup-plugin-handlebars.
How does this differ from rollup-plugin-handlebars
?
At the time of this project's development, rollup-plugin-handlebars
did not support partials.
This project was created to fix that and to add support for a few other features that Mixmax
needed to be compatible with our use of Handlebars template pre-Rollup. We
started to add partial support to
rollup-plugin-handlebars
, then got blocked and made a solution (this plugin) that was specific
to our needs, then worked to make this more generic again (we think). We kept this as a separate
project since the code had become by that point very different.