Build any view with these amazing template engines for NodeJS

Template engines make it easy to render views, for emails, screens, or anything else
Feature Image

Building dynamic websites with APIs is something we all are familiar with as modern-day web developers. Node.js, especially, makes it really easy to set up API backends quickly and connect them with the client-side web applications. But did you know that Node allows the application of template engines as an alternative way for rendering web pages?

As opposed to the API-based website building approach, template engines allow you to render pages with dynamic content on the server-side. They offer flexibility when you’re working with pages that rely heavily on data retrieved from databases. Especially when building static websites, template engines can improve the development process by enabling code reuse.

Just like its name suggests, the primary building block of a template engine-based website is the template. Each page template defines the basic structure of a web page using a special syntax and variables. When it’s finally time to render the page, you can pass the exact values of these variables to create a page with details specific to each request.

In Node.js, developers have the opportunity to pick a template engine from dozens of different available options. The most popular among them include:

  • Pug
  • EJS
  • Handlebars
  • Nunjacks
  • doT
  • Mustache
  • Underscore
  • Marko

In today’s article, we will talk about the first four template engines in the above list, Pug, EJS, Handlebars, and Nunjacks, to provide you a glimpse into working with template engines and using them for building incredibly powerful web pages.


Pug

Pug , formerly known as Jade, is one of the most used template engines in Node. It provides an indentation-based syntax for adding content to a page. With Pug, you can use multiple control structures within the code, including conditionals and loops.

Here’s a simple web page we’ve 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 enclosing tags in its syntax. It then uses indentation to derive the hierarchy, considering indented elements as children of the upper element.

Assigning a CSS class to an element is as simple as declaring their names with a preceding dot.

div.navbar

You can also add a class of an element as a regular attribute. It gives you the freedom to write Javascript to determine the value of the attribute.

div(class=logged ? "logged" : "anon")

We have added the URLs of anchor tags following a similar logic.

a(href="/"+field.name)

Accessing Variables

Our Pug template uses two variables, fields and user, to create the page structure. Accessing their values inside the template can happen in two ways.

If the variable value is the only content assigned to an HTML element or attribute, we can use the equal sign to get the job done.

title=titlevar

Otherwise, we can use the #{var} syntax to access the variable value. It is the method our example has used on several occasions.

h1 Welcome to our website, #{user}

Looping Over Arrays

We can iterate over an array variable in a Pug template using the following syntax.

each field in fields 
    li.nav-item  
         a.nav-link(href="/"+field.name) #{field.name}

Rendering Pug Templates in Express

The popular Node.js framework, Express, provides a set of dedicated methods to introduce and use template engines on the server-side of a web app. For this, we will first put our Pug template in a file with .pug extension and store it in a directory named views in the project folder. Let’s give our template file the name, index.pug.

Then, we can install Pug in our project using npm.

npm install pug

Now, we can set up the view engine and the dedicated views directory in our 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 coming to the “/” route of our web 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});
});

Notice how we are passing the variable values as an argument to the render method. This will allow Pug to replace the variable names with their actual values and render the final HTML content.

When we start the Node app and visit the URL, “localhost:3000?username=Smith”, we get to see the following rendered content on the web page.

Demo website built with NodeJS templates

Demo website built with NodeJS templates

Adding Partials

Partials are a special feature most template engines today provide for reusing code snippets. They allow us to declare reused components separately and repeatedly include them in other templates.

In our example, the navbar is a component we need to reuse when creating different pages in the app. Therefore, instead of going through the pain of rewriting its code in each page file, we can create a partial for the navbar to make it easier to reuse.

Let’s create a separate template file for the navbar named 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 partial in our index page is as simple as using a special keyword named “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

Handlebars is an extension of another popular template engine in Node, Mustache. Unlike Pug, both Handlebars and Mustache are logic-less template engines: they don’t support logic-based conditionals or loops in the template code. It forces you to keep the logic separated from the presentation of a page, making the codebase easier to test and maintain.

Another difference Handlebars has with Pug is that it uses regular HTML syntax to build the page structure instead of relying on indentation. We have shown below how to create a page with the same content as the last one using Handlebars syntax. Since its syntax is closer to HTML, building a template with Handlebars is quite 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 with two brackets on each side.

<h1>Welcome to our website, {{user}}</h1>

Handlebars also supports iterating through an array with the following syntax.

{{#each fields}}
    <li class="nav-item">
        <a class="nav-link" href="/{{name}}">{{name}}</a>
     </li>
{{/each}}

Inside the each-like iteration helper, we have direct access to the properties of each object stored in the array.

Rendering Handlebars Templates with Express

To use Handlebars with Express, first, we should install it using npm.

npm install hbs

Then, the process of setting up Handlebars as the view engine and rendering template page follows similar steps to what 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");
});

Adding Partials

In Handlebars, we have to register the partials first before using them inside a template. For this, let’s first create a separate directory named “partials” inside the views directory to store partials files.

Inside the partials directory, we add the code for the navbar component in a file named 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>

Then, we can register the partials directory inside the application code.

const hbs = require("hbs");
hbs.registerPartials(path.join(__dirname, "views/partials"));

Now, when we include the partial component 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

EJS is another popular Node.js template engine that uses HTML-like syntax. It allows you to use plain Javascript, with variables and programming logic, inside the template to control its structure.

EJS provides a set of tags for including Javascript code in a template. Each unique tag determines how the code included affects the final rendered output of the template. Here, we have listed a few tags you’ll often get to use when creating web pages with EJS.

  • <% Handles the control flow of the code using conditionals, loops, etc. It doesn’t output any value to the template.
  • <%= Outputs the value calculated inside the tag to the template. It escapes any HTML code.
  • <%- Outputs an unescaped value to the template.
  • <%# Comment tag

Now, let’s see how we can convert out Node application’s home page into 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 the basic template. Then, everything from accessing variables to iterating through arrays is executed using regular Javascript code declared inside the special tags we discussed before.

Rendering EJS Templates with Express

The rendering process follows a similar path to what we did with previous template engines. First, we install EJS using npm.

npm install ejs

Then, set EJS as the 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");
});

Adding Partials

Adding partials with EJS is similar to how we implemented this with Pug. We start by creating a new partials file, views/partials/navbar.ejs, with navbar code. Then, we can include the partial in the main template of the home page 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

Nunjucks is a powerful template engine built by Mozilla that you can use with Node.js. It’s fast and allows asynchronous loading of content when rendering web pages. It supports HTML syntax similar to Handlebars and EJS and uses a special {% %} tag for declaring control operations.

Let’s see how we can convert our web page into a Nunjucks template in the following example.

{# 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 this code snippet shows, Nunjucks allows us to access variables inside tags with double brackets. When defining control operations such as for loops, we should use the {% %} tags and follow the syntax specified in its official templating document .

Rendering Nunjucks Templates with Express

We can install Nunjucks easily with npm.

npm install nunjucks

Rendering Nunjucks templates is a little different from what we did in the previous sections: we have to follow a Nunjucks configuration step in addition to setting the view engine and rendering pages.

//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");
});

Adding Partials

Adding partials in Nunjucks is executed just as we did with the previous templating tools. After adding the navbar code to a new file named “navbar.njk” in the partials folder, we can add it in the home page 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>

Wrapping Up

In today’s article, we talked about using template engines with Node.js to build web applications. I hope that this post was a good introduction for you to Node template engines. And if you already have had experience working with them, please tell us about your favorite template engine in our comments section.

Programming Javascript Typescript NodeJS