Building dynamic websites using APIs is something that is familiar to us modern web developers. Node.js, in particular, makes it very easy to quickly set up API backends and connect them with client web applications. But did you know that Node allows the application template engine as an alternative way to render web pages?
Contrary to the API-based approach to building websites, the templating engine allows you to render pages with dynamic content on the server side. They provide flexibility when you’re working with pages that rely heavily on data retrieved from a database. Especially when building static websites, the template engine can improve the development process by enabling code reuse.
As the name suggests, the main building block of a website based on a template engine is a template. Each page template uses special syntax and variables to define the basic structure of a web page. When you finally want to render a page, you can pass the exact values of these variables to create a page with details specific to each request.
What Are the Common NodeJS Template Engines? In Node.js, developers have the opportunity to choose a template engine from dozens of different options available. Some of the most popular include:
- Pug
- EJS
- Handlebars
- Nunjacks
- doT
- Mustache
- Underscore
- Marko
In today’s compilation of the best NodeJS templating engines article, we’ll discuss the first four templating engines on the list above, Pug, EJS, Handlebars, and Nunjacks, to give you an idea of how to use templating engines and use them to build very powerful web pages.
Pug
Which NodeJS templating engine is the best? Pug, formerly known as Jade, is one of the most commonly used templating engines in Node.js. It provides an indentation-based syntax for adding content to a page. With PUG, you can use multiple control structures in your code, including conditions and loops.
Here’s a simple web page we created with the help of Pug and Bootstrap CSS.
doctype html
html
head
meta(name='viewport', content='width=device-width')
link(rel="stylesheet", href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css")
title Home Page
body
div.navbar.navbar-expand.navbar-light.bg-warning
ul.navbar-nav.mb-2
li.nav-item
a.nav-link(href="/") Home
each field in fields
li.nav-item
a.nav-link(href="/"+field.name) #{field.name}
div.container.text-left.mt-3
h1 Welcome to our website, #{user}
div.message
p Find anything you want on our website.
As you can see, Pug uses HTML element names directly without including tags in their syntax. It then derives the hierarchy using indentation, treating the indented element as a child of the upper-level element.
Assigning CSS classes to elements is as simple as declaring their names with the dots that precede them.
div.navbar
You can also add an element’s class as a general property. It gives you the freedom to write Javascript to determine the value of a property.
div(class=logged ? "logged" : "anon")
We followed a similar logic to add the anchor-tagged URLs.
a(href="/"+field.name)
Access variables
Our PUG template uses two variable fields and users to create the page structure. There are two ways to access the values within a template.
If the variable value is the only thing assigned to an HTML element or attribute, we can use an equal sign to get the job done.
title=titlevar
Otherwise, we can use the #{var} syntax to access the variable values. Here’s how our example is used multiple times.
h1 Welcome to our website, #{user}
Circular array
We can use the following syntax to iterate over the array variables in the PUG template.
each field in fields
li.nav-item
a.nav-link(href="/"+field.name) #{field.name}
Render the PUG template in Express
What Are the Common NodeJS Template Engines? Express, a popular Node.js framework, provides a set of specialized ways to ingest and use the templating engine on the server side of a web application. To do this, we first put the PUG template in a file with a .pug extension and store it in a directory called views in the project folder. Let’s give our template file a name, index.pug.
We can then use npm to install PUG in our project.
npm install pug
We can now set up the view engine and a dedicated view directory in the initial application code.
//app.js
const express = require("express");
const path = require("path");
const app = express();
//Set view engine name and template directory path
app.set("view engine", "pug");
app.set("views", path.join(__dirname, "views"));
app.listen(3000 || process.env.PORT, () => {
console.log("Server started listening");
});
Finally, we should render the index.pug file for requests that go into our web application’s “/” route.
fields = [{name: "Technology"}, {name: "News"}, {name: "Sports"}, {name: "Travel"}];
app.get("/", (req, res) => {
const username = req.query.username;
res.render("index", {user: username, fields: fields});
});
Notice how we pass the variable value as an argument to the render method. This will allow Pug to replace variable names with their actual values and render the final HTML content.
When we start the Node application and visit the URL “localhost:3000?username=Smith”, we see the following rendering on the web page.
Add sections
Sections are special features for reusing code snippets that most templating engines offer today. They allow us to declare reused components separately and repeatedly include them in other templates.
In our example, the navigation bar is a component that we need to reuse when creating different pages in our application. So instead of rewriting the code in each page file, we can create a section for the navigation bar to make it easier to reuse.
Let’s create a separate template file for the navigation bar called navbar.pug.
//views/navbar.pug
div.navbar.navbar-expand.navbar-light.bg-warning
ul.navbar-nav.mb-2
li.nav-item
a.nav-link(href="/") Home
each field in fields
li.nav-item
a.nav-link(href="/"+field.name) #{field.name}
Using this section in our index pages is as simple as using a special keyword called “include”.
//views/index.pug
body
include navbar
div.container.text-left.mt-3
h1 Welcome to our website, #{user}
div.message
p Find anything you want on our website.
Handlebars
Best NodeJS Templating Engine Collection: Handlebars is an extension of Mustache, another popular templating engine in Node. Unlike Pug, both Handlebars and Mustache are logic-free templating engines: they don’t support logic-based conditions or loops in template code. It forces you to separate the logic from the presentation of the page, making the codebase easier to test and maintain.
Another difference between Handlebars and Pug is that it uses regular HTML syntax to structure the page, rather than relying on indentation. We’ve shown below how to use the Handlebars syntax to create a page with the same content as the previous one. Since its syntax is closer to HTML, building a template with Handlebars is very intuitive.
{{!-- views/index.hbs --}}
<!DOCTYPE html>
<html>
<head>
<meta name='viewport', content='width=device-width'/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"/>
<title>Home Page</title>
</head>
<body>
<div class="navbar navbar-expand navbar-light bg-warning">
<ul class="navbar-nav mb-2">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
{{#each fields}}
<li class="nav-item">
<a class="nav-link" href="/{{name}}">{{name}}</a>
</li>
{{/each}}
</ul>
</div>
<div class="container text-left mt-3">
<h1>Welcome to our website, {{user}}</h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
</html>
When accessing variables in Handlebars, we should enclose the variable name in two parentheses on each side.
<h1>Welcome to our website, {{user}}</h1>
Handlebars also supports traversing arrays using the following syntax.
{{#each fields}}
<li class="nav-item">
<a class="nav-link" href="/{{name}}">{{name}}</a>
</li>
{{/each}}
In an iteration helper like each, we have direct access to the properties of each object stored in the array.
Use Express to render the Handlebars template
To use Handlebars in Express, first, we should install it using npm.
npm install hbs
Then, the process of setting the Handlebars as the view engine and rendering the template page follows similar steps as we did with Pug.
//app.js
const express = require("express");
const path = require("path");
const app = express();
app.set("view engine", "hbs");
app.set("views", path.join(__dirname, "views"));
fields = [{name: "Technology"}, {name: "News"}, {name: "Sports"}, {name: "Travel"}];
app.get("/", (req, res) => {
const username = req.query.username;
res.render("index", {user: username, fields: fields});
});
app.listen(3000 || process.env.PORT, () => {
console.log("Server started listening");
});
Add sections
Which NodeJS templating engine is the best? In Handlebars, we have to register sections before we can use them in a template. To do this, let’s first create a separate directory called “partials” in the view directory to store some of the files.
In the partials directory, we add the code of the navbar component to a file called navbar.hbs.
{{! views/partials/navbar.hbs}}
<div class="navbar navbar-expand navbar-light bg-warning">
<ul class="navbar-nav mb-2">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
{{#each fields}}
<li class="nav-item">
<a class="nav-link" href="/{{name}}">{{name}}</a>
</li>
{{/each}}
</ul>
</div>
We can then register the partials directory in the application code.
const hbs = require("hbs");
hbs.registerPartials(path.join(__dirname, "views/partials"));
Now, when we include a subset of components in a template, Handlebars will recognize it and import the component code to render the web page.
<body>
{{>navbar}} {{! including the partial}}
<div class="container text-left mt-3">
<h1>Welcome to our website, {{user}}</h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
EJS
What Are the Common NodeJS Template Engines? EJS is another popular Node.js templating engine that uses HTML-like syntax. It allows you to control the structure of a template using plain Javascript with variables and programming logic inside it.
EJS provides a set of tags for including Javascript code in a template. Each unique tag determines how the included code affects the final render output of the template. Here, we’ve listed some of the tags that you often use when creating web pages with EJS.
<%
Control flow that handles code using conditions, loops, and so on. It doesn’t output any value to the template.<%=
Outputs the calculated values within the label to the template. It escapes any HTML code.<%-
Output unescaped values to a template.<%#
Comment tags
Now, let’s see how to convert the home page of a Node app to an EJS template.
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head>
<meta name='viewport', content='width=device-width'/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"/>
<title>Home Page</title>
</head>
<body>
<div class="navbar navbar-expand navbar-light bg-warning">
<ul class="navbar-nav mb-2">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<% fields.forEach(field => { %>
<li class="nav-item">
<a class="nav-link" href=<%= "/"+ field.name %>><%= field.name %></a>
</li>
<% }) %>
</ul>
</div>
<div class="container text-left mt-3">
<h1>Welcome to our website, <%= user %></h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
</html>
As you can see in this code, EJS uses HTML syntax to build basic templates. Everything from accessing variables to traversing arrays is then executed using regular Javascript code declared inside special tags that we discussed earlier.
Best NodeJS Template Engine Collection: Render EJS Templates with Express
The rendering process follows a similar path as we did with the previous templating engine. First, we install EJS using npm.
npm install ejs
Then, set the EJS as your application’s view engine and render index.ejs with variable values before sending it to the client.
//app.js
const express = require("express");
const path = require("path");
const app = express();
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
fields = [{name: "Technology"}, {name: "News"}, {name: "Sports"}, {name: "Travel"}];
app.get("/", (req, res) => {
const username = req.query.username;
res.render("index", {user: username, fields: fields});
});
app.listen(3000 || process.env.PORT, () => {
console.log("Server started listening");
});
Add sections
Using EJS to add parts is similar to what we do with Pug. Let’s start by creating a new section file with the navbar code, views/partials/navbar.ejs. We can then include sections in the main template of the homepage like this.
<!-- views/index.ejs -->
<body>
<%- include ("partials/navbar") %>
<div class="container text-left mt-3">
<h1>Welcome to our website, <%= user %></h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
Nunjucks
Which NodeJS templating engine is the best? Nunjucks is a powerful templating engine built by Mozilla that you can use with Node.js. It’s fast and allows content to be loaded asynchronously while rendering web pages. It supports HTML syntax similar to Handlebars and EJS, and uses special {% %} tags to declare control actions.
In the following example, let’s see how to convert our web page into a Nunjucks template.
{# views/index.njk #}
<!DOCTYPE html>
<html>
<head>
<meta name='viewport', content='width=device-width'/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"/>
<title>Home Page</title>
</head>
<body>
<div class="navbar navbar-expand navbar-light bg-warning">
<ul class="navbar-nav mb-2">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
{% for field in fields %}
<li class="nav-item">
<a class="nav-link" href="/{{field.name}}">{{field.name}}</a>
</li>
{% endfor %}
</ul>
</div>
<div class="container text-left mt-3">
<h1>Welcome to our website, {{ user }}</h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
</html>
As you can see in this code snippet, Nunjucks allows us to access variables inside tags with double parentheses. When defining control actions such as for loops, we should use the {% %} tag and follow the syntax specified in their official template documentation.
Use Express to render the Nunjucks template
We can easily install Nunjucks using npm.
npm install nunjucks
What Are the Common NodeJS Template Engines? Rendering the Nunjucks template is a bit different than what we did in the previous sections: in addition to setting up the view engine and rendering the page, we also have to follow the Nunjucks configuration steps.
//app.js
const express = require("express");
const path = require("path");
const nunjucks = require("nunjucks");
const app = express();
app.set('view engine', 'njk');
//configure Nunjucks by passing the express app and setting autoescape to true
nunjucks.configure('views', {
autoescape: true,
express: app
})
fields = [{name: "Technology"}, {name: "News"}, {name: "Sports"}, {name: "Travel"}];
app.get("/", (req, res) => {
const username = req.query.username;
res.render("index", {user: username, fields: fields});
});
app.listen(3000 || process.env.PORT, () => {
console.log("Server started listening");
});
Add sections
Adding sections in Nunjucks is done in the same way we did with the previous templating tool. Once we’ve added the navigation bar code to a new file named “navbar.njk” in the partials folder, we can add it to the homepage template using the include keyword.
<body>
{% include "partials/navbar.njk" %}
<div class="container text-left mt-3">
<h1>Welcome to our website, {{ user }}</h1>
<div class="message">
<p>Find anything you want on our website.</p>
</div>
</div>
</body>
Summary of the best NodeJS template engine collection
In today’s article, we talked about using the templating engine and Node.js to build web applications. I hope this article is a good introduction to the Node templating engine. If you already have experience using them, please let us know your favorite template engine in our comment section.