• Stars
    star
    458
  • Rank 95,591 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 12 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Express handlebars template engine with inheritance, partials, i18n and async helpers.

express-hbs

Express handlebars template engine with multiple layouts, blocks and cached partials.

v2.0.0

Version 2 was a rewrite and cleanup, with no known breaking changes. Lots of bugs were fixed which may have subtly changed behaviour.

Full details: https://github.com/TryGhost/express-hbs/releases/tag/2.0.0

v1.0.0 Breaking Changes

If you're upgrading from v0.8.4 to v1.0.0 there are some potentially breaking changes to be aware of:

  1. Handlebars @v4.0.5 - please see the handlebars v4.0 compatibility notes
  2. The file extension for partial files must now match the extension configured in extname - please see the PR

Usage

To use with express 4.

var hbs = require('express-hbs');

// Use `.hbs` for extensions and find partials in `views/partials`.
app.engine('hbs', hbs.express4({
  partialsDir: __dirname + '/views/partials'
}));
app.set('view engine', 'hbs');
app.set('views', __dirname + '/views');

To use with express 3 is the same as above, except use hbs.express3

app.engine('hbs', hbs.express3({
  partialsDir: __dirname + '/views/partials'
}));

Options for #express3 and #express4

hbs.express4({
  partialsDir: "{String/Array} [Required] Path to partials templates, one or several directories",

  // OPTIONAL settings
  blockHelperName: "{String} Override 'block' helper name.",
  contentHelperName: "{String} Override 'contentFor' helper name.",
  defaultLayout: "{String} Absolute path to default layout template",
  extname: "{String} Extension for templates & partials, defaults to `.hbs`",
  handlebars: "{Module} Use external handlebars instead of express-hbs dependency",
  i18n: "{Object} i18n object",
  layoutsDir: "{String} Path to layout templates",
  templateOptions: "{Object} options to pass to template()",
  beautify: "{Boolean} whether to pretty print HTML, see github.com/einars/js-beautify .jsbeautifyrc",

  // override the default compile
  onCompile: function(exhbs, source, filename) {
    var options;
    if (filename && filename.indexOf('partials') > -1) {
      options = {preventIndent: true};
    }
    return exhbs.handlebars.compile(source, options);
  }
});

Syntax

To mark where layout should insert page

{{{body}}}

To declare a block placeholder in layout

{{{block "pageScripts"}}}

To define block content in a page

{{#contentFor "pageScripts"}}
  CONTENT HERE
{{/contentFor}}

Layouts

There are three ways to use a layout, listed in precedence order

  1. Declarative within a page. Use handlebars comment

    {{!< LAYOUT}}
    

    Layout file resolution:

    If path starts with '.'
        LAYOUT is relative to template
    Else If `layoutsDir` is set
        LAYOUT is relative to `layoutsDir`
    Else
        LAYOUT from path.resolve(dirname(template), LAYOUT)
    
  2. As an option to render

    ⚠️ This creates a potential security vulnerability:

    Do not use this option in conjunction with passing user submitted data to res.render e.g. res.render('index', req.query). This allows users to read arbitrary files from your filesystem!

    res.render('veggies', {
      title: 'My favorite veggies',
      veggies: veggies,
      layout: 'layout/veggie'
    });

    This option also allows for layout suppression (both the default layout and when specified declaratively in a page) by passing in a falsey Javascript value as the value of the layout property:

    res.render('veggies', {
      title: 'My favorite veggies',
      veggies: veggies,
      layout: null // render without using a layout template
    });

    Layout file resolution:

    If path starts with '.'
        layout is relative to template
    Else If `layoutsDir` is set
        layout is relative to `layoutsDir`
    Else
        layout from path.resolve(viewsDir, layout)
    
  3. Lastly, use defaultLayout if specified in hbs configuration options.

Layouts can be nested: just include a declarative layout tag within any layout template to have its content included in the declared "parent" layout. Be aware that too much nesting can impact performances, and stay away from infinite loops!

Helpers

Synchronous helpers

hbs.registerHelper('link', function(text, options) {
  var attrs = [];
  for(var prop in options.hash) {
    attrs.push(prop + '="' + options.hash[prop] + '"');
  }
  return new hbs.SafeString(
    "<a " + attrs.join(" ") + ">" + text + "</a>"
  );
});

in markup

{{{link 'barc.com' href='http://barc.com'}}}

Asynchronous helpers

hbs.registerAsyncHelper('readFile', function(filename, cb) {
  fs.readFile(path.join(viewsDir, filename), 'utf8', function(err, content) {
    cb(new hbs.SafeString(content));
  });
});

in markup

{{{readFile 'tos.txt'}}}

i18n support

Express-hbs supports i18n

var i18n = require('i18n');

// minimal config
i18n.configure({
    locales: ['en', 'fr'],
    cookie: 'locale',
    directory: __dirname + "/locales"
});

app.engine('hbs', hbs.express3({
    // ... options from above
    i18n: i18n,  // registers __ and __n helpers
}));
app.set('view engine', 'hbs');
app.set('views', viewsDir);

// cookies are needed
app.use(express.cookieParser());

// init i18n module
app.use(i18n.init);

Engine Instances

Create isolated engine instances with their own cache system and handlebars engine.

var hbs = require('express-hbs');
var instance1 = hbs.create();
var instance2 = hbs.create();

Template options

The main use case for template options is setting the handlebars "data" object - this creates global template variables accessible with an @ prefix.

Template options can be set in 3 ways. When setting global template options they can be passed as config on creation of an instance, and they can also be updated used the updateTemplateOptions(templateOptions) method of an instance. To set template options for an individual request they can be set on res.locals using the helper method updateLocalTemplateOptions(locals, templateOptions).

Both of these methods have a companion method getTemplateOptions() and getLocalTemplateOptions(locals), which should be used when extending or merging the current options.

Example

in File app.js

// http://expressjs.com/api.html#app.locals
app.locals({
    'PROD_MODE': 'production' === app.get('env')
});

File views/layout/default.hbs

<html>
  <head>
    <title>{{title}}</title>
    <link type="text/css" rel="stylesheet" href="/css/style.css"/>
    {{{block "pageStyles"}}}
  </head>
  <body>
    {{{body}}}

    {{> scripts}}

    {{#if PROD_MODE}}
    {{{block 'googleAnalyticsScripts'}}}
    {{/if}}

  </body>
</html>

File views/index.hbs

{{!< default}}

{{#contentFor 'pageStyles'}}
<style>
  .clicker {
    color: blue;
  };
</style>
{{/contentFor}}

<h1>{{title}}</h1>
<p class="clicker">Click me!</p>

To run example project

npm install -d
node example/app.js

Testing

The test suite requires the grunt-cli package:

npm install -g grunt-cli
npm install -d

Once everything's installed, just run:

npm test

Credits

Inspiration and code from donpark/hbs

Big thanks to all CONTRIBUTORS

License

The MIT License (MIT)

Copyright (c) 2012-2023 Barc, Inc., Ghost Foundation - Released under the MIT license.

More Repositories

1

Ghost

Independent technology for modern publishing, memberships, subscriptions and newsletters.
JavaScript
44,370
star
2

node-sqlite3

SQLite3 bindings for Node.js
PLpgSQL
6,218
star
3

Casper

The default theme for Ghost
CSS
2,535
star
4

gatsby-starter-ghost

A starter template to build lightning fast websites with Ghost & Gatsby
JavaScript
1,042
star
5

Admin

Ghost's admin client
JavaScript
627
star
6

Ghost-CLI

CLI Tool for installing & updating Ghost
JavaScript
433
star
7

Starter

A development starter theme for Ghost
CSS
359
star
8

eleventy-starter-ghost

A starter template to build websites with Ghost & Eleventy
Nunjucks
335
star
9

action-deploy-theme

:octocat: Deploy your Ghost theme with Github Actions
JavaScript
335
star
10

Dawn

A minimal newsletter theme for Ghost
CSS
263
star
11

London

A free, open source theme for Ghost
Handlebars
258
star
12

Ghost-Android

🤖 Ghost for Android
Java
237
star
13

Ghost-Vagrant

Vagrant setup for developing Ghost
Puppet
226
star
14

Massively

A free, open source theme for Ghost
SCSS
216
star
15

Editorial

A free, open source theme for Ghost
SCSS
185
star
16

gatsby-source-ghost

Source plugin for pulling data into Gatsby.js from the Ghost Public API.
JavaScript
176
star
17

Lyra

A paid-members theme for Ghost
CSS
176
star
18

Roon

The official Roon theme for Ghost
CSS
142
star
19

Koenig

Components of Ghost's Editor
JavaScript
116
star
20

Alto

A clean, minimalist theme featuring a light and dark mode for Ghost
Handlebars
113
star
21

docs

Ghost's official documentation
JavaScript
112
star
22

Ghost-App

Includes for Ghost Apps
JavaScript
111
star
23

knex-migrator

DB migration tool for knex.js
JavaScript
100
star
24

SDK

Tools for working with Ghost's APIs
JavaScript
100
star
25

Ghost-Config

Cross-platform meta data and configurations
JavaScript
82
star
26

Ease

A minimal documentation theme for Ghost
Handlebars
80
star
27

generator-ghost

Generate Ghost blogs and themes using Yeoman.
JavaScript
78
star
28

gscan

Ghost theme scanner - checks for errors and feature support
JavaScript
75
star
29

Edge

A visually aesthetic portfolio theme for Ghost
Handlebars
73
star
30

Edition

The newsletter theme for Ghost
JavaScript
73
star
31

Pico

A paid members publishing theme for Ghost
CSS
69
star
32

Themes

A monorepo for Ghost themes
Handlebars
67
star
33

Wave

A podcast theme for Ghost
Handlebars
66
star
34

Portal

Drop-in script to add membership features in a Ghost theme
JavaScript
56
star
35

Source

The default theme for Ghost
CSS
54
star
36

Dope

A unique tag-based theme for Ghost
CSS
53
star
37

Ruby

A multi-column theme with a unique card layout for Ghost
Handlebars
44
star
38

Headline

A local news theme for Ghost
Handlebars
41
star
39

Journal

A newsletter theme for Ghost
Handlebars
41
star
40

GQL

Filter query language for working with Ghost's API
JavaScript
39
star
41

nodecmsguide

Your guide to Node.js content management systems
JavaScript
37
star
42

Slimer-hubot

A bot who lives in IRC
CoffeeScript
36
star
43

wp-ghost-exporter

A WordPress plugin to export content to Ghost
PHP
30
star
44

Solo

A personal theme for Ghost
Handlebars
29
star
45

migrate

JavaScript
27
star
46

Members

JavaScript
24
star
47

Ghost-Editor

Ghost's Mobiledoc Editor
23
star
48

Argon

A simple publishing theme for Ghost
CSS
22
star
49

api-demos

Demo scripts showing how to use Ghost's Admin and Content APIs to accomplish common tasks.
JavaScript
22
star
50

gctools

Command line utilities for working with Ghost content
JavaScript
20
star
51

framework

A collection of handy components for building Node.js applications
JavaScript
20
star
52

bookshelf-relations

A bookshelf plugin which handles relationships.
JavaScript
18
star
53

Tribeca

A free theme for Ghost
CSS
16
star
54

Ignition

Basic configuration and tooling shared across applications
JavaScript
16
star
55

algolia

JavaScript
16
star
56

Ghost-Storage-Base

Base storage adapter for Ghost
JavaScript
14
star
57

Utils

JavaScript
14
star
58

slimer

Tools for working on Ghost & the surrounding ecosystem
JavaScript
11
star
59

vscode

TypeScript
11
star
60

roon-i18n

Roon Internationalization
Ruby
10
star
61

NQL-old

NQL Toolkit: Query data using the NQL Language
JavaScript
9
star
62

action-update-posts

GitHub action for making scheduled changes to posts (e.g. toggling featured)
JavaScript
9
star
63

passport-ghost

Passport adapter for logging in with Ghost.org
JavaScript
8
star
64

Bulletin

A newsletter theme for Ghost
Handlebars
7
star
65

eslint-plugin-ghost

Shared eslint configurations
JavaScript
7
star
66

comments-ui

Drop-in script for comments in Ghost
JavaScript
6
star
67

Digest

A newsletter theme for Ghost
Handlebars
6
star
68

static

Static remote assets for Ghost sites
6
star
69

digitalocean-1-click

DigitalOcean 1-Click App
Shell
6
star
70

action-ghost-release

🚢 GitHub Action to release Ghost
JavaScript
6
star
71

Deploy

Custom shipitjs plugin for deploying
JavaScript
6
star
72

mongo-knex

JavaScript
6
star
73

sodo-search

Drop-in script for search in Ghost
JavaScript
6
star
74

NQL

JavaScript
4
star
75

Zap

An ultra-minimal Ghost theme
CSS
4
star
76

Zapier

Ghost <-> Zapier Integration
JavaScript
4
star
77

slimer-dashboard

GitHub Dashboard built in Apollo
JavaScript
3
star
78

Taste

Handlebars
3
star
79

cropper

JavaScript
2
star
80

nameservers

2
star
81

bunyan-rotating-file-stream

Rotate bunyan logs based on time period and file-size threshold
JavaScript
2
star
82

Actions

GitHub Actions to power Ghost development
JavaScript
2
star
83

label-actions

Tools for managing Ghost's OSS repositories
JavaScript
1
star
84

.github

1
star
85

Analytics

JavaScript
1
star
86

salt-formula-sensu

Salt formula for configuring Sensu.
1
star
87

Core

JavaScript
1
star
88

action-trigger-metric

JavaScript
1
star
89

architecture-diagrams

Set of diagrams and docs explainig architecture of Ghost
1
star