2. Pug
1. Introduction
As web designers or developers, we likely all have to write our fair share of HTML. And while this is not the most difficult task, it can often feel a little boring or repetitive. This is where the Pug HTML preprocessor comes in.
HTML is also static, which means that if you want to display dynamic data (fetched from an API, for example), you invariably end up with a mishmash of HTML stings inside JavaScript. This can be a nightmare to debug and to maintain. Pug is a template engine for Node and for the browser. It compiles to HTML and has a simplified syntax, which can make you more productive and your code more readable. Pug makes it easy both to write reusable HTML, as well as to render data pulled from a database or API.
1.1 History
It’s also worth noting that Pug used to be called Jade until it was forced to change its name due to a trademark claim in 2015. The name change took effect with version 2.0.
1.2 What is pug used for
A template engine is a program which is responsible for compiling a template (that can be written using any one of a number of languages) into HTML. The template engine will normally receive data from an external source, which it will inject into the template it’s compiling. This is illustrated by the following diagram.
2. Example
Install Pug Package
npm i pug
Create a file hello.pug
and place it in .\views
folder
DirectorytestNodeProject/
Directoryviews/
- hello.pug
- server.js
- package.json
In server.js
set the view engine to pug
const express = require('express');const app = express()
// Set the view engineapp.set( 'view engine', 'pug' ); // by default, it will look for pug templates in views folder
// Optional: To change the location of views to another directoryapp.set('views', './views')
// Set handler for the root '/'app.get('/', (req, res) => { res.render('hello', {theTitle: 'This is the Title'}); // this will look for the file 'hello.pug' in './views' folder // second parameter to render(...) method is optional});
app.listen(3000, function(){ console.log('Listening on port 3000')});
doctype htmlhtml(lang='en') head title Hello, World! #{theTitle || "Default Value"} //- if `theTitle` parameter is not defined when //- rending `hello.pug` use the default value "Default Value" body h1 Hello, World! div.remark p Pug rocks!
<!DOCTYPE html><html lang="en"> <head> <title>Hello, World! This is the Title</title> </head> <body> <h1>Hello, World!</h1> <div class="remark"> <p>Pug rocks!!</p> </div> </body></html>
Rendered output, when http://localhost:3000/
is accessed
Another Example
doctype htmlhtml(lang='en') head title Hello, World! #{theTitle || "Default Value"} //- if `theTitle` parameter is not defined when //- rending `hello.pug` use the default value "Default Value" body div(class="custom", id="myid") Inside div but before paragraph p paragraph part 01 | paragraph part 02 (continuation) | outside paragraph but inside div
div.remark p Pug rocks!
<!DOCTYPE html><html lang="en"> <head> <title>Hello, World! This is the Title</title> </head> <body> <div class="custom" id="myid"> Inside div but before paragraph <p>paragraph part 01 paragraph part 02 (continuation)</p> outside paragraph but inside div </div> <div class="remark"> <p>Pug rocks!!</p> </div> </body></html>
Rendered output, when http://localhost:3000/
is accessed
3. DOCTYPE
You can use Pug to generate a number of document type declarations.
For example doctype html will compile to <!DOCTYPE html>
, the standard HTML5 doctype, whereas doctype strict will give us <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
. Pug will do its best to ensure that its output is valid for the document type.
4. Tags
As mentioned, Pug doesn’t have any closing tags and relies on indentation for nesting. This might take a small amount of getting used to, but once you do, it makes for clean and readable code. By way of an example:
nav navbar-default div h1 My Website! ul li a Home li a Page 1 li a Page 2 input
Rendered output
<nav> <div> <h1>My Website!</h1> </div> <ul> <li><a>Home</a></li> <li><a>Page 1</a></li> <li><a>Page 2</a></li> </ul> <input/></nav>
5. Classes, IDs and Attributes
Classes and IDs are expressed using a .className
and #IDname
notation. For example:
nav#navbar-default div.container-fluid h1.navbar-header My Website!
Pug also offers us a handy shortcut. If no tag is specified, it will assume a <div>
element:
nav#navbar-default .container-fluid h1.navbar-header My Website!
Both of these compile to:
<nav id="navbar-default"> <div class="container-fluid"> <h1 class="navbar-header">My Website!</h1> </div></nav>
5.1 Attributes are added using brackets:
ul li a(href='/') Home li a(href='/page-1') Page 1 li a(href='/page-2') Page 2
input.search( type='text' name='search' placeholder='Enter a search term...' )
This results in the following:
<ul> <li><a href="/">Home</a></li> <li><a href="/page-1">Page 1</a></li> <li><a href="/page-2">Page 2</a></li></ul><input class="search" type="text" name="search" placeholder="Enter a search term..."/>
6. 🧠 Pug Features
6.1 Variables
h1= title
6.2 Conditionals
if user p Welcome, #{user.name}!else p Please log in.
6.3 Loops
ul each item in items li= item
6.3 Mixins (reusable components)
//- In _mixins.pugmixin card(title, content) .card h2= title p= content
//- In pageinclude _mixins.pug+card('Hello', 'This is a card.')
7. Extended Example
Basic Project Structure
Directorymy-app/
Directoryviews/
- layout.pug
- index.pug
- about.pug
Directorypublic/
- styles.css
- app.js
- package.json
const express = require('express');const path = require('path');
const app = express();
// Set view engine to Pugapp.set('view engine', 'pug');app.set('views', path.join(__dirname, 'views'));
// Static filesapp.use(express.static(path.join(__dirname, 'public')));
// Routesapp.get('/', (req, res) => { res.render('index', { title: 'Home', message: 'Welcome to the Pub!' });});
app.get('/about', (req, res) => { res.render('about', { title: 'About', team: ['Nadith', 'Jane', 'John'] });});
// Start serverapp.listen(3000, () => console.log('Server started on http://localhost:3000'));
(optional layout template)
doctype htmlhtml head title= title link(rel="stylesheet", href="/styles.css") body block content
extends layout
block content h1= message p This is the home page.
extends layout
block content h1= title ul each person in team li= person
🎨 Static Assets (CSS, Images)
- Put them in
public/
- Reference with
/path
in Pug
link(rel="stylesheet", href="/styles.css")img(src="/logo.png")