View Engines and Setting Up EJS
Objectives
By the end of this lesson, you should be able to:
- Explain what a view engine is and what problem it solves
- Configure Express to use EJS as its view engine
- Render a view with
res.render, passing it dynamic data
๐ก Why this matters: Module 5 sent plain text and JSON with
res.send()/res.json(). Real HTML pages, with dynamic values plugged into a template, need something more, a view engine renders a template file into HTML on every request.
โ ๏ธ A note on verification: every snippet and every response shown below was actually run and tested with real HTTP requests, using EJS 6.
What a View Engine Does
A view engine takes a template (an HTML file with placeholders for dynamic values) and a data object, and combines them into a final HTML string sent back to the client. Instead of building an HTML string by hand with string concatenation, template files stay readable as HTML, with small, clearly marked spots where dynamic data gets inserted. Express supports many view engines, EJS is the most common for teams already comfortable with plain HTML and JavaScript.
Installing and Configuring EJS
npm install ejs
const express = require('express');
const path = require('path');
const app = express();
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.listen(4101);
app.set('view engine', 'ejs') tells Express which engine to use, EJS doesn’t even need to be require()’d directly, Express detects and uses it automatically once it’s installed and set as the view engine. app.set('views', ...) sets the folder Express looks in for template files, views is the conventional name (Module 4’s path.join builds this path correctly, as always).
Project File Structure
Every lesson in this module builds on the same basic shape, a views folder sitting next to the server file, holding one .ejs file per page:
project/
โโโ package.json
โโโ server.js
โโโ views/
โโโ home.ejs
res.render('home', data), below, looks for views/home.ejs, matching the view name to a file in that folder automatically, this is the whole convention EJS relies on, no separate registration step for each individual view.
Rendering a View
<!-- views/home.ejs -->
<!DOCTYPE html>
<html>
<head><title><%= pageTitle %></title></head>
<body>
<h1>Welcome, <%= userName %>!</h1>
<p>You have <%= itemCount %> items.</p>
</body>
</html>
app.get('/', (req, res) => {
res.render('home', {
pageTitle: 'My App',
userName: 'Erin',
itemCount: 3
});
});
curl http://localhost:4101/
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
<h1>Welcome, Erin!</h1>
<p>You have 3 items.</p>
</body>
</html>
res.render(viewName, data) renders views/home.ejs (the .ejs extension is added automatically), replacing every <%= expression %> with the result of evaluating expression against the data object passed in. This is the core loop of a server-rendered application: a route handler fetches or computes data, then hands it to res.render() instead of res.json().
Try It
- Install EJS, configure Express to use it, and create a
viewsfolder with a template showing a page title and a greeting using two dynamic values. - Render that template from a route, passing in different values, and confirm the resulting HTML reflects them correctly.
- Add a third dynamic value to the same template and route, and confirm it appears correctly without touching anything else.
- Explain, in your own words, what problem a view engine solves that
res.send()with manually built HTML strings doesn’t.
Recap
- A view engine renders a template file plus a data object into final HTML,
app.set('view engine', ...)andapp.set('views', ...)configure it. res.render(viewName, data)renders a template, EJS’s<%= expression %>syntax inserts a value directly into the output.- This replaces
res.send()with manually built HTML strings for any page with real dynamic content.
Next lesson: EJS’s full templating syntax, loops and conditionals inside a template.