Node.js Handlebars
In this short tutorial I am going to install and implement a simple templating engine called Handlebars and I am going to hook it up with Node.js, so we will be able to present our data in nicely formatted HTML documents.
For this tutorial I have gone throught RisingStack’s Node Hero tutorial (the PDF version) and Academind’s video tutorial.
First let’s install express-handlebars, and its types, which is a version of Handlebars tailored specifically for the express framework.
npm install express-handlebars @types/express-handlebars --save
Then, let’s create the following folder structure:
/dist
/src
server.ts
/views
home.hbs
error.hbs
/layouts
main.hbs
In this setup, I am using TypeScript which gets compiled to the dist
folder. We have to also make sure that .hbs
files get copied to dist
as well. For that, I have used the copyfiles package…
npm install copyfiles --save-dev -g
… and added it to my build
script in package.json
file.
"build": "copyfiles -u 1 src/**/*.hbs dist && tsc",
Now that we have our files in place upon compilation, let’s integrate Handlebars to our express application.
// inside server.ts
import * as hbs from "express-handlebars";
import * as path from "path";
app.engine(
"hbs",
hbs({
extname: "hbs",
defaultLayout: "main",
layoutsDir: path.join(__dirname, "views/layouts"),
})
);
app.set("view engine", "hbs");
app.set("views", path.join(__dirname, "views"));
With this configuration we have set the default layout which will be the basic wrapper for our HTML files, the path for our templates, and set handlebars to be our view engine. Now let’s use this engine in a request:
// inside server.ts
app.get("/", (req, res) => {
res.render("home", {
name: "stranger",
featureArray: [
{ feature: "Open-source", makesSense: true },
{ feature: "Feedback-system", makesSense: true },
{ feature: "Potato", makesSense: false },
{
feature: "Written in and with Node.js, TypeScript and other cool tools",
makesSense: true,
},
{ feature: "I like trains", makesSense: false },
],
});
});
With this in place we are going to render the view home
which is going to wrapped in the main
template. We are also going to pass a set of data to the view which we will loop through and present based on a condition.
Let’s write our main
wrapper.
<html>
<head>
<title>Kudos</title>
<link
rel="stylesheet"
href="https://bootswatch.com/yeti/bootstrap.min.css"
/>
</head>
<body>
{{{ body }}}
<footer class="footer">
<div class="container">
<p class="text-muted">
You can also visit the project on
<a href="https://github.com/gaboratorium/kudos" target="_blank"
>GitHub</a
>.
</p>
</div>
</footer>
</body>
</html>
As you have probably guessed it, all the views are going to be injected in the body
handlebar. The triple handlebars indicate that the data passed into it should not escape HTML. Finally, let’s write our home.hbs
as well.
<div class="container">
<div class="page-header">
<h1>Welcome {{ name }} to Kudos</h1>
</div>
<p class="lead">This is a Node.js application currently under development. <a href="https://gaboratorium.github.io" target="_blank">Visit my blog</a> to follow to follow up with the project's progress.</a></p>
<h2>What is this?</h2>
<p>Meanwhile the app is under development at the moment, here are some of the main key characteristics:</p>
<ul>
{{# each featureArray }}
{{# if this.makesSense }}
<li>{{ this.feature }}</li>
{{/ if}}
{{/ each}}
</ul>
</div>
One thing to note here, is that whenever we start a new handlebars code block, we have to indicate it with a hash (#
), and close the tag with a slash (/
) prefix. Now if we run our application (in my case compile TS, copy .hbs
files running the build
script), we should be able to visit the app in our browser and see our templates being used.