UNPKG

7.5 kBMarkdownView Raw
1# express-hbs
2
3Express handlebars template engine with multiple layouts, blocks and cached partials.
4
5## v2.0.0
6
7Version 2 was a rewrite and cleanup, with no known breaking changes. Lots of bugs were fixed which may have subtly changed behaviour.
8
9Full details: https://github.com/TryGhost/express-hbs/releases/tag/2.0.0
10
11## v1.0.0 Breaking Changes
12
13If you're upgrading from v0.8.4 to v1.0.0 there are some potentially breaking changes to be aware of:
14
151. Handlebars @v4.0.5 - please see the [handlebars v4.0 compatibility notes](https://github.com/wycats/handlebars.js/blob/master/release-notes.md#v400---september-1st-2015)
162. The file extension for partial files must now match the extension configured in `extname` - please see [the PR](https://github.com/TryGhost/express-hbs/pull/88)
17
18## Usage
19
20To use with express 4.
21```js
22var hbs = require('express-hbs');
23
24// Use `.hbs` for extensions and find partials in `views/partials`.
25app.engine('hbs', hbs.express4({
26 partialsDir: __dirname + '/views/partials'
27}));
28app.set('view engine', 'hbs');
29app.set('views', __dirname + '/views');
30```
31To use with express 3 is the same as above, except use hbs.express3
32
33```js
34app.engine('hbs', hbs.express3({
35 partialsDir: __dirname + '/views/partials'
36}));
37```
38
39Options for `#express3` and `#express4`
40
41```js
42hbs.express4({
43 partialsDir: "{String/Array} [Required] Path to partials templates, one or several directories",
44
45 // OPTIONAL settings
46 blockHelperName: "{String} Override 'block' helper name.",
47 contentHelperName: "{String} Override 'contentFor' helper name.",
48 defaultLayout: "{String} Absolute path to default layout template",
49 extname: "{String} Extension for templates & partials, defaults to `.hbs`",
50 handlebars: "{Module} Use external handlebars instead of express-hbs dependency",
51 i18n: "{Object} i18n object",
52 layoutsDir: "{String} Path to layout templates",
53 templateOptions: "{Object} options to pass to template()",
54 beautify: "{Boolean} whether to pretty print HTML, see github.com/einars/js-beautify .jsbeautifyrc",
55
56 // override the default compile
57 onCompile: function(exhbs, source, filename) {
58 var options;
59 if (filename && filename.indexOf('partials') > -1) {
60 options = {preventIndent: true};
61 }
62 return exhbs.handlebars.compile(source, options);
63 }
64});
65```
66
67## Syntax
68
69To mark where layout should insert page
70
71 {{{body}}}
72
73To declare a block placeholder in layout
74
75 {{{block "pageScripts"}}}
76
77To define block content in a page
78
79 {{#contentFor "pageScripts"}}
80 CONTENT HERE
81 {{/contentFor}}
82
83## Layouts
84
85There are three ways to use a layout, listed in precedence order
86
871. Declarative within a page. Use handlebars comment
88
89 {{!< LAYOUT}}
90
91 Layout file resolution:
92
93 If path starts with '.'
94 LAYOUT is relative to template
95 Else If `layoutsDir` is set
96 LAYOUT is relative to `layoutsDir`
97 Else
98 LAYOUT from path.resolve(dirname(template), LAYOUT)
99
1002. As an option to render
101
102 ```js
103 res.render('veggies', {
104 title: 'My favorite veggies',
105 veggies: veggies,
106 layout: 'layout/veggie'
107 });
108 ```
109
110 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:
111
112 ```js
113 res.render('veggies', {
114 title: 'My favorite veggies',
115 veggies: veggies,
116 layout: null // render without using a layout template
117 });
118 ```
119
120 Layout file resolution:
121
122 If path starts with '.'
123 layout is relative to template
124 Else If `layoutsDir` is set
125 layout is relative to `layoutsDir`
126 Else
127 layout from path.resolve(viewsDir, layout)
128
1293. Lastly, use `defaultLayout` if specified in hbs configuration options.
130
131Layouts can be nested: just include a declarative layout tag within any layout
132template to have its content included in the declared "parent" layout. Be
133aware that too much nesting can impact performances, and stay away from
134infinite loops!
135
136## Helpers
137
138### Synchronous helpers
139
140```js
141hbs.registerHelper('link', function(text, options) {
142 var attrs = [];
143 for(var prop in options.hash) {
144 attrs.push(prop + '="' + options.hash[prop] + '"');
145 }
146 return new hbs.SafeString(
147 "<a " + attrs.join(" ") + ">" + text + "</a>"
148 );
149});
150```
151
152in markup
153```
154{{{link 'barc.com' href='http://barc.com'}}}
155```
156
157### Asynchronous helpers
158
159```js
160hbs.registerAsyncHelper('readFile', function(filename, cb) {
161 fs.readFile(path.join(viewsDir, filename), 'utf8', function(err, content) {
162 cb(new hbs.SafeString(content));
163 });
164});
165```
166
167in markup
168```
169{{{readFile 'tos.txt'}}}
170```
171
172
173## i18n support
174
175Express-hbs supports [i18n](https://github.com/mashpie/i18n-node)
176
177```js
178var i18n = require('i18n');
179
180// minimal config
181i18n.configure({
182 locales: ['en', 'fr'],
183 cookie: 'locale',
184 directory: __dirname + "/locales"
185});
186
187app.engine('hbs', hbs.express3({
188 // ... options from above
189 i18n: i18n, // registers __ and __n helpers
190}));
191app.set('view engine', 'hbs');
192app.set('views', viewsDir);
193
194// cookies are needed
195app.use(express.cookieParser());
196
197// init i18n module
198app.use(i18n.init);
199```
200
201## Engine Instances
202
203Create isolated engine instances with their own cache system and handlebars engine.
204
205```js
206var hbs = require('express-hbs');
207var instance1 = hbs.create();
208var instance2 = hbs.create();
209```
210
211## Template options
212
213The main use case for template options is setting the handlebars "data" object - this creates global template variables accessible with an `@` prefix.
214
215Template options can be set in 3 ways. When setting global template options they can be [passed as config on creation of an instance](https://github.com/barc/express-hbs#usage), 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)`.
216
217Both of these methods have a companion method `getTemplateOptions()` and `getLocalTemplateOptions(locals)`, which should be used when extending or merging the current options.
218
219## Example
220
221in File `app.js`
222
223```js
224// http://expressjs.com/api.html#app.locals
225app.locals({
226 'PROD_MODE': 'production' === app.get('env')
227});
228
229```
230
231File `views/layout/default.hbs`
232
233```html
234<html>
235 <head>
236 <title>{{title}}</title>
237 <link type="text/css" rel="stylesheet" href="/css/style.css"/>
238 {{{block "pageStyles"}}}
239 </head>
240 <body>
241 {{{body}}}
242
243 {{> scripts}}
244
245 {{#if PROD_MODE}}
246 {{{block 'googleAnalyticsScripts'}}}
247 {{/if}}
248
249 </body>
250</html>
251```
252
253
254File `views/index.hbs`
255
256```html
257{{!< default}}
258
259{{#contentFor 'pageStyles'}}
260<style>
261 .clicker {
262 color: blue;
263 };
264</style>
265{{/contentFor}}
266
267<h1>{{title}}</h1>
268<p class="clicker">Click me!</p>
269```
270
271To run example project
272
273 npm install -d
274 node example/app.js
275
276
277## Testing
278
279The test suite requires the `grunt-cli` package:
280
281 npm install -g grunt-cli
282 npm install -d
283
284Once everything's installed, just run:
285
286 npm test
287
288
289## Credits
290
291Inspiration and code from [donpark/hbs](https://github.com/donpark/hbs)
292
293Big thanks to all [CONTRIBUTORS](https://github.com/TryGhost/express-hbs/contributors)
294
295
296## License
297
298The MIT License (MIT)
299
300Copyright (c) 2012-2020 Barc, Inc., Ghost Foundation - Released under the [MIT license](LICENSE).