UNPKG

7.76 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 ## ⚠️ This creates a potential security vulnerability:
103
104 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!
105
106 ```js
107 res.render('veggies', {
108 title: 'My favorite veggies',
109 veggies: veggies,
110 layout: 'layout/veggie'
111 });
112 ```
113
114 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:
115
116 ```js
117 res.render('veggies', {
118 title: 'My favorite veggies',
119 veggies: veggies,
120 layout: null // render without using a layout template
121 });
122 ```
123
124 Layout file resolution:
125
126 If path starts with '.'
127 layout is relative to template
128 Else If `layoutsDir` is set
129 layout is relative to `layoutsDir`
130 Else
131 layout from path.resolve(viewsDir, layout)
132
1333. Lastly, use `defaultLayout` if specified in hbs configuration options.
134
135Layouts can be nested: just include a declarative layout tag within any layout
136template to have its content included in the declared "parent" layout. Be
137aware that too much nesting can impact performances, and stay away from
138infinite loops!
139
140## Helpers
141
142### Synchronous helpers
143
144```js
145hbs.registerHelper('link', function(text, options) {
146 var attrs = [];
147 for(var prop in options.hash) {
148 attrs.push(prop + '="' + options.hash[prop] + '"');
149 }
150 return new hbs.SafeString(
151 "<a " + attrs.join(" ") + ">" + text + "</a>"
152 );
153});
154```
155
156in markup
157```
158{{{link 'barc.com' href='http://barc.com'}}}
159```
160
161### Asynchronous helpers
162
163```js
164hbs.registerAsyncHelper('readFile', function(filename, cb) {
165 fs.readFile(path.join(viewsDir, filename), 'utf8', function(err, content) {
166 cb(new hbs.SafeString(content));
167 });
168});
169```
170
171in markup
172```
173{{{readFile 'tos.txt'}}}
174```
175
176
177## i18n support
178
179Express-hbs supports [i18n](https://github.com/mashpie/i18n-node)
180
181```js
182var i18n = require('i18n');
183
184// minimal config
185i18n.configure({
186 locales: ['en', 'fr'],
187 cookie: 'locale',
188 directory: __dirname + "/locales"
189});
190
191app.engine('hbs', hbs.express3({
192 // ... options from above
193 i18n: i18n, // registers __ and __n helpers
194}));
195app.set('view engine', 'hbs');
196app.set('views', viewsDir);
197
198// cookies are needed
199app.use(express.cookieParser());
200
201// init i18n module
202app.use(i18n.init);
203```
204
205## Engine Instances
206
207Create isolated engine instances with their own cache system and handlebars engine.
208
209```js
210var hbs = require('express-hbs');
211var instance1 = hbs.create();
212var instance2 = hbs.create();
213```
214
215## Template options
216
217The main use case for template options is setting the handlebars "data" object - this creates global template variables accessible with an `@` prefix.
218
219Template 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)`.
220
221Both of these methods have a companion method `getTemplateOptions()` and `getLocalTemplateOptions(locals)`, which should be used when extending or merging the current options.
222
223## Example
224
225in File `app.js`
226
227```js
228// http://expressjs.com/api.html#app.locals
229app.locals({
230 'PROD_MODE': 'production' === app.get('env')
231});
232
233```
234
235File `views/layout/default.hbs`
236
237```html
238<html>
239 <head>
240 <title>{{title}}</title>
241 <link type="text/css" rel="stylesheet" href="/css/style.css"/>
242 {{{block "pageStyles"}}}
243 </head>
244 <body>
245 {{{body}}}
246
247 {{> scripts}}
248
249 {{#if PROD_MODE}}
250 {{{block 'googleAnalyticsScripts'}}}
251 {{/if}}
252
253 </body>
254</html>
255```
256
257
258File `views/index.hbs`
259
260```html
261{{!< default}}
262
263{{#contentFor 'pageStyles'}}
264<style>
265 .clicker {
266 color: blue;
267 };
268</style>
269{{/contentFor}}
270
271<h1>{{title}}</h1>
272<p class="clicker">Click me!</p>
273```
274
275To run example project
276
277 npm install -d
278 node example/app.js
279
280
281## Testing
282
283The test suite requires the `grunt-cli` package:
284
285 npm install -g grunt-cli
286 npm install -d
287
288Once everything's installed, just run:
289
290 npm test
291
292
293## Credits
294
295Inspiration and code from [donpark/hbs](https://github.com/donpark/hbs)
296
297Big thanks to all [CONTRIBUTORS](https://github.com/TryGhost/express-hbs/contributors)
298
299
300## License
301
302The MIT License (MIT)
303
304Copyright (c) 2012-2021 Barc, Inc., Ghost Foundation - Released under the [MIT license](LICENSE).