Pug with Express
So far Pug has run at build time: a script created the HTML files once. On a server it is different — Express (a popular web framework for Node.js) renders the page from the template again on every request and can insert fresh data, for example from a database. Express itself is covered in detail in the Express course of the JavaScript section; here you only see what connects it to Pug.
Installing
Create a new project and install Express together with Pug:
mkdir cafe-server
cd cafe-server
npm init -y
npm pkg set type=module
npm install express pugThis lesson targets Express 5, the current version this command installs.
The server
Create the file src/server.js:
// src/server.js
import express from "express";
const app = express();
app.set("view engine", "pug");
const menu = [
{ name: "Espresso", price: 2 },
{ name: "Cappuccino", price: 3 },
];
app.get("/", (req, res) => {
res.render("index", { title: "Morning Café", menu });
});
app.listen(3000, () => {
console.log("Server running: http://localhost:3000");
});The line app.set("view engine", "pug") tells Express that templates are written in Pug. res.render() finds the template by its name without the extension, passes it the data object and sends the finished HTML as the response.
The template
Express looks for templates in the views/ folder in the project root. Create views/index.pug:
doctype html
html(lang="en")
head
meta(charset="utf-8")
title= title
body
h1= title
ul
each item in menu
li #{item.name} — $#{item.price}The fields of the object from res.render() became the variables title and menu, just like the data from build.js before.
Running it
node src/server.jsOpen http://localhost:3000 and you will see the heading and the list of drinks. The browser receives this HTML:
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Morning Café</title></head><body><h1>Morning Café</h1><ul><li>Espresso — $2</li><li>Cappuccino — $3</li></ul></body></html>Express does not turn on pretty, so the HTML arrives on one line, which makes the page smaller. The browser developer tools are a more convenient way to read the code: they show it with indentation.
Layouts and mixins on the server
Everything from the previous lessons works here too: put layout.pug, mixins.pug and the includes/ folder into views/, and start pages with extends layout.pug. Paths in extends and include are still counted from the current file.
Common mistake
Inserting what visitors sent with != or !{...}: a name from a form, the text of a review. On a server such data arrives all the time, and any unescaped insertion opens the door to an XSS attack. Output user data only with = and #{...}.