Skip to main content

Handlebars

Link: Handlebars

You need to install the handlebars package:

npm i -D handlebars

preprocessor: 'handlebars'​

For example, there is the template src/views/page/home.hbs

<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{{> header }}
<div class="container">
<h1>Handlebars</h1>
<div>{{ arraySize persons }} persons:</div>
<ul class="person">
{{#each persons}}
{{> person person=.}}
{{/each}}
</ul>
</div>
{{> footer }}
</body>
</html>

Where the {{> header }}, {{> person person=.}} and {{> footer }} are partials.

Define the preprocessor as handlebars:

const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = {
plugins: [
new HtmlBundlerPlugin({
entry: {
// define templates here
index: {
import: 'src/views/pages/home.hbs', // => dist/index.html
// pass data to template as an object
// data: { title: 'Handlebars', persons: [...] },
// OR define the data file
data: 'src/views/pages/homeData.js',
},
},
// use handlebars templating engine
preprocessor: 'handlebars',
// define handlebars options
preprocessorOptions: {
partials: ['src/views/partials'],
helpers: {
arraySize: (array) => array.length,
},
},
}),
],
};

Source code of the example

Open in StackBlitz

preprocessorOptions​

The preprocessor has built-in include helper, to load a partial file directly in a template without registration of partials.

The include helper has the following de facto standard options:

{
// defaults process.cwd(), root path for includes with an absolute path (e.g., /file.html)
root: path.join(__dirname, 'src/views/'), // defaults process.cwd()
// defaults [], an array of paths to use when resolving includes with relative paths
views: [
'src/views/includes', // relative path
path.join(__dirname, 'src/views/partials'), // absolute path
],
},

For example, there are template page and partials:

src/views/
├── page/
│ └── home.html
├── includes/
│ ├── gallery.html
│ └── teaser.html
├── partials/
│ ├── footer.html
│ └── menu/
│ ├── nav.html
│ └── top/
│ └── desktop.html

Include the partials in the src/views/page/home.html template with the include helper:

<!-- root path -->
{{ include '/includes/gallery' }}

<!-- views paths -->
{{ include 'menu/top/desktop' }}
{{ include 'menu/nav' }}
{{ include 'teaser' }}
{{ include 'footer' }}

The include helper automatically resolves .html and .hbs extensions, it can be omitted.

The runtime option​

The path to the handlebars runtime library. The path can be absolute or relative to node_modules directory. Defaults runtime file is handlebars/runtime. This options is used only by import templates in JavaScript, in compile mode.

The partials option​

Type: Array<string>|Object Default: []

If you use the partials syntax {{> footer }} to include a file, then use the partials option. Partials will be auto-detected in paths recursively and registered under their relative paths, without an extension.

{
preprocessor: 'handlebars',
preprocessorOptions: {
// an array of relative or absolute paths to partials
partials: [
'src/views/includes', // relative path
path.join(__dirname, 'src/views/partials'), // absolute path
],
},
},

For example, if the partial path is the src/views/partials then the file src/views/partials/menu/top/desktop.html will have the partial name menu/top/desktop.

You can define all partials manually using the option as an object:

{
// define partials manually
partials: {
teaser: path.join(__dirname, 'src/views/includes/teaser.html'),
gallery: path.join(__dirname, 'src/views/includes/gallery.html'),
footer: path.join(__dirname, 'src/views/partials/footer.html'),
'menu/nav': path.join(__dirname, 'src/views/partials/menu/nav.html'),
'menu/top/desktop': path.join(__dirname, 'src/views/partials/menu/top/desktop.html'),
},
},

Include the partials in the src/views/page/home.html template:

{{> menu/top/desktop }}
{{> menu/nav }}
{{> teaser }}
{{> gallery }}
{{> footer }}

The helpers option​

Type: Array<string>|Object Default: []

When the helpers is an array of relative or absolute paths to helpers, then the name of a helper is the relative path to the helper file without an extension.

For example, there are helper files:

src/views/helpers/bold.js
src/views/helpers2/italic.js
src/views/helpers2/wrapper/span.js

The preprocessor options:

{
preprocessor: 'handlebars',
preprocessorOptions: {
// an array of relative or absolute paths to helpers
helpers: [
'src/views/helpers',
'src/views/helpers2',
],
},
},

Usage of helpers:

{{#bold}}The bold text.{{/bold}} {{#italic}}The italic text.{{/italic}}

<!-- the helper with namespace `wrapper/span` -->
{{#[wrapper/span]}}The text wrapped with span tag.{{/[wrapper/span]}}
note
  • The helper located in a subdirectory, e.g. wrapper/span.js will be available in template as [wrapper/span].
  • When helper name contain the / slash, then the helper name must be wrapped with the [].

You can define helpers manually using name: function object:

{
preprocessor: 'handlebars',
preprocessorOptions: {
// define helpers manually
helpers: {
bold: (options) => new Handlebars.SafeString(`<strong>${options.fn(this)}</strong>`),
},
},
},

This plugin has own build-in helpers:

  • include - includes a template file relative to paths defined in views option, the default path is the project root path
{{include 'TEMPLATE_FILE'}}
  • assign - creates a new named variable or override old. You can define many variables. The variables are available in included partials.
{{assign title='Homepage' header='Home'}}
{{> layout}}

layout.hbs

<title>{{title}}</title>
<h1>{{header}}</h1>
  • partial and block:

partial - defines the block content

{{#partial 'BLOCK_NAME'}}BLOCK_CONTENT{{/partial}}

block - outputs the block content, it can be used in another partial file, e.g. in a layout partial

{{#block 'BLOCK_NAME'}}default content or empty{{/block}}

For the complete list of Handlebars compile options see here.