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");
}
}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
- EJS
- PUG (jade)
- Handlebars (hbs)
- AngularJS (not Angular 2)
- Vue JS
Today’s current best template language is Vue.js
EJS
This is a npm library
npm install ejsHow 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
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>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>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>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>// 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>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-mateNow, 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!








