Skip to content

Commit

Permalink
Add support for Handlebars compile options and data variables (#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
mohd-akram authored Sep 12, 2023
1 parent e3e39d5 commit 39f16ec
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 9 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,24 @@ To use partials in handlebars you will need to pass the names and paths in the o
}
```

You can specify [compile options](https://handlebarsjs.com/api-reference/compilation.html#handlebars-compile-template-options) as well:

```js
options: {
compileOptions: {
preventIndent: true
}
}
```

To access `defaultContext` and `reply.locals` as [`@data` variables](https://handlebarsjs.com/api-reference/data-variables.html):

```js
options: {
useDataVariables: true
}
```

To use layouts in handlebars you will need to pass the `layout` parameter:

```js
Expand Down
26 changes: 17 additions & 9 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function fastifyView (fastify, opts, next) {
const includeViewExtension = opts.includeViewExtension || false
const viewExt = opts.viewExt || ''
const prod = typeof opts.production === 'boolean' ? opts.production : process.env.NODE_ENV === 'production'
const defaultCtx = opts.defaultContext || {}
const defaultCtx = opts.defaultContext
const globalLayoutFileName = opts.layout

function templatesDirIsValid (_templatesDir) {
Expand Down Expand Up @@ -200,7 +200,7 @@ function fastifyView (fastify, opts, next) {
data = globalOptions.useHtmlMinifier.minify(data, globalOptions.htmlMinifierOptions || {})
}
if (type === 'handlebars') {
data = engine.compile(data)
data = engine.compile(data, globalOptions.compileOptions)
}
lru.set(file, data)
callback(null, data)
Expand Down Expand Up @@ -483,8 +483,16 @@ function fastifyView (fastify, opts, next) {
return
}

const options = Object.assign({}, globalOptions)
data = Object.assign({}, defaultCtx, this.locals, data)
let options

if (globalOptions.useDataVariables) {
options = {
data: defaultCtx ? Object.assign({}, defaultCtx, this.locals) : this.locals
}
} else {
data = Object.assign({}, defaultCtx, this.locals, data)
}

// append view extension
page = getPage(page, 'hbs')
const requestedPath = getRequestedPath(this)
Expand All @@ -496,7 +504,7 @@ function fastifyView (fastify, opts, next) {

if (prod) {
try {
const html = template(data)
const html = template(data, options)
if (!this.getHeader('content-type')) {
this.header('Content-Type', 'text/html; charset=' + charset)
}
Expand All @@ -505,18 +513,18 @@ function fastifyView (fastify, opts, next) {
this.send(e)
}
} else {
getPartials(type, { partials: options.partials || {}, requestedPath }, (err, partialsObject) => {
getPartials(type, { partials: globalOptions.partials || {}, requestedPath }, (err, partialsObject) => {
if (err) {
this.send(err)
return
}

try {
Object.keys(partialsObject).forEach((name) => {
engine.registerPartial(name, engine.compile(partialsObject[name]))
engine.registerPartial(name, engine.compile(partialsObject[name], globalOptions.compileOptions))
})

const html = template(data)
const html = template(data, options)

if (!this.getHeader('content-type')) {
this.header('Content-Type', 'text/html; charset=' + charset)
Expand Down Expand Up @@ -719,7 +727,7 @@ function fastifyView (fastify, opts, next) {
return
}
Object.keys(partialsObject).forEach((name) => {
engine.registerPartial(name, engine.compile(partialsObject[name]))
engine.registerPartial(name, engine.compile(partialsObject[name], globalOptions.compileOptions))
})
next()
})
Expand Down
1 change: 1 addition & 0 deletions templates/body-data.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>{{ @text }}</p>
76 changes: 76 additions & 0 deletions test/test-handlebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,82 @@ test('fastify.view with handlebars engine with missing partials path in producti
})
})

test('reply.view with handlebars engine with compile options', t => {
t.plan(6)
const fastify = Fastify()
const handlebars = require('handlebars').create()
const compileOptions = { preventIndent: true, strict: true }
const data = { text: 'hello\nworld' }

fastify.register(require('../index'), {
engine: {
handlebars
},
options: {
compileOptions,
partials: { body: './templates/body.hbs' }
}
})

fastify.get('/', (req, reply) => {
reply.view('./templates/index-with-partials.hbs', data)
})

fastify.listen({ port: 0 }, err => {
t.error(err)
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err, response, replyBody) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(response.headers['content-length'], '' + replyBody.length)
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
t.equal(handlebars.compile(fs.readFileSync('./templates/index-with-partials.hbs', 'utf8'), compileOptions)(data), replyBody.toString())
fastify.close()
})
})
})

test('reply.view with handlebars engine with useDataVariables', t => {
t.plan(6)
const fastify = Fastify()
const handlebars = require('handlebars').create()
const compileOptions = { strict: true }
const data = { text: 'text' }

fastify.register(require('../index'), {
engine: {
handlebars
},
options: {
compileOptions,
useDataVariables: true,
partials: { body: './templates/body-data.hbs' }
}
})

fastify.get('/', (req, reply) => {
reply.locals = data
reply.view('./templates/index-with-partials.hbs', null)
})

fastify.listen({ port: 0 }, err => {
t.error(err)
sget({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err, response, replyBody) => {
t.error(err)
t.equal(response.statusCode, 200)
t.equal(response.headers['content-length'], '' + replyBody.length)
t.equal(response.headers['content-type'], 'text/html; charset=utf-8')
t.equal(handlebars.compile(fs.readFileSync('./templates/index-with-partials.hbs', 'utf8'), compileOptions)(null, { data }), replyBody.toString())
fastify.close()
})
})
})

test('reply.view with handlebars engine with layout option', t => {
t.plan(6)
const fastify = Fastify()
Expand Down

0 comments on commit 39f16ec

Please sign in to comment.