handlebars.js
handlebars.js copied to clipboard
Load precompiled templates from Typescript
For anyone trying to load precompiled templates from typescript (for sending an email for instance):
- You have to precompile with the -c option:
handlebars templates/*.handlebars -f templates/precompiled.js -c handlebars/runtime
- Load the Handlebars runtime and then the templates file:
import * as Handlebars from 'handlebars/runtime';
import './templates/precompiled'; // load templates
- Use as always:
Handlebars.templates['name-of-file-without-extension'](data)
I hope this helps you and you don't waste many hours like me.
Thanks, I have marked this as "docs-needed". Maybe it will find its way into https://github.com/handlebars-lang/docs/ some day
Would that go like maybe under integrations? https://handlebarsjs.com/installation/integrations.html
What is templates/precompiled.js
?
Saw a couple of different of answers floating around... Replace double back ticks with single back ticks!
To generate a template use this
const Handlebars = require('handlebars'); const fs = require('fs'); const addTemplate = async (templateName) => { const templateFile = await fs.promises.readFile(./path/to/template); const templateString= templateFile.toString(); const precompiledPath = ``./precompiled/${templateName}.js``; const precompiledFileString = Handlebars.precompile(templateString).toString(); await fs.promises.writeFile(path.join(precompiledPath, ``${templateName}.js``), ``module.exports = ${precompiledFileString}``, {encoding: 'utf8'}); }
To read from the template use this
const Handlebars = require('handlebars/runtime'); const profileTemplate = require('./precompiled/profile.js') const getTemplate = (templateName, data) => { const template = Handlebars.template(templateName); const compiledTemplate = template(data); return compiledTemplate }
I just spent a solid day on this. Gonna post here and maybe it'll make it into the docs one day. I have a specific need of loading precompiled templates only if I need them, also because I don't know if they'll be available until I evaluate a specific conditional. This is for a lambda@edge function in AWS.
Here is an example template that i have in a file called before.handlebars
{"bar": "{{header "user-agent"}}"}
I've run the following command against this file
npx handlebars before.handlebars -f before.precompiled.js -c handlebars
To use this:
import Handlebars from 'handlebars'
...redacted....
if (config.eventing && config.eventing.events?.before_decision) {
// https://stackoverflow.com/a/36299373/3689435
require("./before.precompiled.js")
const populated = Handlebars.templates["before"]({
headers: request.headers,
})
console.log(populated)
}
I'm not that familiar with the difference between handlebars
and handlebars/runtime
. Just make sure that which ever one you choose to use, the import at the top of the file and the -c
flag on the cli are the same, else this won't work.
My lambda@edge function is written in typescript and compiled with esbuild and once I figure this out, I had no problem. I don't need any special bundlers or loaders.
@ddouglas Although not related to this issue, I would like to suggest not to use Handlebars to generate JSON output.
It is much easier and probably more efficient to use
const populated = JSON.stringify({
bar: request.headers["user-agent"]
})
in your case.
If you would like to see this in the docs, feel free to open a PR at https://github.com/handlebars-lang/docs/.
@papasmile I would put it after https://handlebarsjs.com/installation/precompilation.html#precompiling-templates-inside-nodejs I would not consider "TypeScript" an integration. This is more related to pre-compilation than to build-systems.