Sitemap

Template Engines

(Node Series Bonus)

Template Engine

Template engines allow you to dynamically generate HTML by injecting data into templates. They are essential for server-side rendering (SSR) in Express.js applications.

Here is an example of how you insert HTML code without using any template engines.

import express from "express";
import path from "node:path";
import { fileURLToPath } from "url";
import { URL } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();

const html=`<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>**title**</h1>
</body>
</html>
`

const titles=["React","HTML","Vue"]
let index=0
app.get('/', (req,res)=>{
const title=titles[index]
index++;
const update=html.replace("**title**",title)
res.send(update)
});



app.listen(3000, serverListener);

function serverListener(err) {
if (err) {
console.log("error", err);
}else{
console.log("Server Started");
}
}
Press enter or click to view image in full size
Press enter or click to view image in full size

Now, in the above, u can see we refresh and get new data, but each time we are manually replacing the title inthe HTML content. Now to resolve this issue and make it happen automatically, template engines were introduced ejs pug(rare) and handlebars

Other template engines

  1. EJS
  2. PUG (jade)
  3. Handlebars (hbs)
  4. AngularJS (not Angular 2)
  5. Vue JS

Today’s current best template language is Vue.js

EJS

This is a npm library

npm install ejs

How to use?

We have to tell Node we are using a template engine by adding these two lines. In our main file.

//what engine i am using
app.set('view-engine',ejs)
// this tells where we are setting the templates
//where ejs file will be there
// do add template folder in your project
app.set("views",path.join(__dirname,"template"))

Common use of the app.set function

Press enter or click to view image in full size

Now, to use it inside your index.js

import express from "express";
import path from "node:path";
import { fileURLToPath } from "url";
import { URL } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();

app.set('view-engine',"ejs")//what engine i am using
// this tells where we are setting the templates
//where ejs file will be there
// do add template folder in your project
app.set("views",path.join(__dirname,"template"))


app.get('/', (req,res)=>{
res.render("home.ejs")
});



app.listen(3000, serverListener);

function serverListener(err) {
if (err) {
console.log("error", err);
}else{
console.log("Server Started");
}
}

create an HTML file with the extension instead of HTML, it will be ejs. This is our home. ejs file, which has HTML content

<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Initial Template</h1>
</body>
</html>
Press enter or click to view image in full size

Now, how to use JavaScript inside it

We use <% %> for adding js into our template

//to add each line of js in between
<% %>

//used to render value from variable , where variable is between
<%= %>

//used to render comment this will not show inside the render on screen
<%# %>
//insdide ejs file
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Initial Template</h1>
<% const total = 10 + 20; const isAdmin = true %>
<p>Total: <%= total %></p>
</body>
</html>
Press enter or click to view image in full size

Using injected variables

Now, to pass value from your express file itself, we pass values as an object inside the render function

//second arguments takes and object to use it inside template
render("EJS FIle",{key:value})
import express from "express";
import path from "node:path";
import { fileURLToPath } from "url";
import { URL } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();

app.set('view-engine',"ejs")
app.set("views",path.join(__dirname,"template"))


app.get('/', (req,res)=>{
// also take second argument as object
// for variables
res.render("home.ejs",{user:"shubham"})
});



app.listen(3000, serverListener);

function serverListener(err) {
if (err) {
console.log("error", err);
}else{
console.log("Server Started");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Initial Template</h1>
<% const total = 10 + 20; const isAdmin = true %>
<p>Total: <%= total %></p>
<p>User: <%= user %></p>
</body>
</html>
Press enter or click to view image in full size

For every JavaScript variable code u have to wrap it around <% %> for each and every line.

only one variable can be used inside a pair , if u pass a array it will convert it to toString value and render it same for object that will be [object object ] and u can also use ternary operation as only one value will be passed.

Nested Objects

res.render("profile", {
user: {
name: "Rahul",
address: {
city: "Delhi"
}
}
});


<p>Name: <%= user.name %></p>
<p>City: <%= user.address.city %></p>

Looping

How to loop inside template

<ul>
<% products.forEach(function(product) { %>
<li><%= product.name %> - $<%= product.price %></li>
<% }); %>
</ul>
import express from "express";
import path from "node:path";
import { fileURLToPath } from "url";
import { URL } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();

app.set('view-engine',"ejs")
app.set("views",path.join(__dirname,"template"))


app.get('/', (req,res)=>{
res.render("home.ejs",{user:"shubham",
products:[{name:"pen",price:10},{name:"pencil",price:5}]})
});


app.listen(3000, serverListener);
function serverListener(err) {
if (err) {
console.log("error", err);
}else{
console.log("Server Started");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Initial Template</h1>
<% const total = 10 + 20; const isAdmin = true %>
<p>Total: <%= total %></p>
<p>User: <%= user %></p>
<ul>
<% products.forEach(function(product) { %>
<li><%= product.name %> - $<%= product.price %></li>
<% }); %>
</ul>
</body>
</html>
Press enter or click to view image in full size
// For loop
<% for(let i = 0; i < 5; i++) { %>
<p>Item <%= i %></p>
<% } %>

If/Else

In this each statement will be wrapped that is only javascript in between the tags

<% if (user) { %>
<h2>Welcome, <%= user.name %></h2>
<% } else { %>
<h2>Please log in</h2>
<% } %>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>Initial Template</h1>
<% const total = 10 + 20; const isAdmin = true %>
<p>Total: <%= total %></p>
<p>User: <%= user %></p>
<ul>
<% products.forEach(function(product) { %>
<li><%= product.name %> - $<%= product.price %></li>
<% }); %>
</ul>
<% if (user) { %>
<h2>Welcome, <%= user.name %></h2>
<% } else { %>
<h2>Please log in</h2>
<% } %>
</body>
</html>
Press enter or click to view image in full size

Ternary

<p>Status: <%= isAdmin ? "Admin" : "User" %></p>

Function Call

res.render("home", {
price: 100,
format: function (p) {
return `$${p.toFixed(2)}`;
},
});
<p>Price: <%= format(price) %></p>

Partials

Let’s say I want to have a common code in all my templates

Get Shubham Gupta’s stories in your inbox

Join Medium for free to get updates from this writer.

Create a file inside a folder partial and add header file inside it

<header><h1>My App</h1></header>

Now to include this in the template file

<%- include('partials/header') %>
<p>Main content here</p>

All partials have variable access that is passed from Express

Rules

include() must use relative path (no leading /). EJS always resolves paths relative to the views/ folder (by default).

//If you set:
app.set('views', path.join(__dirname, 'views'));

//then this
<%- include('partials/header') %>

//else
<%- include(path.join(__dirname, 'views', 'partials', 'header.ejs')) %>

Use <%- include %> to render HTML (not escape it).

Layouts

Now, there is also an issue with includes. Let's say we want to use header partial in multiple files, so the layout comes in, which is a separate library

npm install ejs-mate

Now, tell the node how to use the layout inside your index.js

import ejsMate from "ejs-mate";
app.set("view engine", "ejs");
app.set("views", "./templates");
app.engine("ejs", ejsMate);

Now u can have a common layout. Now create a layout folder and inside from notes inside the layout folder.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title><%= title %></title>
</head>
<body>
<main>
<%= title %> <%- body %>
<!-- Page-specific content goes here -->
</main>
</body>
</html>

Now I want to inject content in this layout, which is controlled by <%- body%>, similar to having children props in React, here the body will be dynamic

Now, inside the main EJS file, we just need to have this

<% layout('layout/filename')%>
//layout is the reserved keyword here
<% layout('main') %>

<h1>This is the home page</h1>

This is also server-side rendering. This was done a few years ago.

Layout vs Partials

In partials

<%- include('partials/header') %>
<h1>Home Page</h1>
<%- include('partials/footer') %>

In layout

<% layout('layout') %>

<h1>This is my page</h1>

If you’d like to be in the know, subscribe, clap, like, and share. Cheers!