{ Server-side Templating with Pug. }

Objectives:

By the end of this chapter, you should be able to:

  • Define what server side templating is
  • Render templates using pug
  • Use pug to create dynamic templates

Rendering Templates

So far we have only seen how to respond by sending text, but when building server-side applications, we usually want to send back HTML or JSON / XML (if we're building an RESTful API).

If we want to simply send HTML back we can use response.sendFile, but since we are using server-side templates, we will be using a method called render.

In order to do that, we need to make use of a templating engine (a tool for dynamically rendering HTML using server data). There are quite a few we can use with Node.js including ejs, but we will be using one called pug (formerly known as jade).

Before we introduce the pug syntax, let's first start a new project and see what we need to include. By default, express expects a folder containing templates to be called views. Instead of overriding that default, we will also create a folder called views.

mkdir learn_pug && cd learn_pug
touch app.js
npm init -y
npm install express pug # notice we are installing pug as well!
mkdir views
touch views/index.pug

Let's now get started in our app.js:

const express = require("express");
const app = express();

app.set("view engine", "pug"); // notice here we are telling express to render views using the pug templating engine.

app.get("/", (request, response) => {
  return response.render("index"); // here we are rendering a template called index.pug inside of the views folder
});

app.listen(3000, () => {
  console.log(
    "The server has started on port 3000. Head to localhost:3000 in the browser and see what's there!"
  );
});

Working with pug

The most important thing to understand about pug is that it is an indentation-based syntax. To nest elements inside of each other we simply indent the inner elements.

const express = require("express");
const app = express();

const colors = ["red", "green", "blue"];

app.set("view engine", "pug"); // notice here we are telling express to render views using the pug templating engine.

app.get("/", (request, response) => {
  const firstName = "Elie";
  return response.render("index", { name: firstName }); // here we are rendering a template called index.pug inside of the views folder. We are also passing a value to the template called "name". Inside of the template, the value of that variable will be the value of the firstName variable, which is "Elie"
});

app.get("/colors", (request, response) => {
  // {colors} is ES2015 object shorthand notation for {colors: colors}
  return response.render("data", { colors }); // here we are rendering a template called data.pug inside of the views folder. We are also passing a value to the template called "colors". Inside of the template, the value of that variable will be the value of the colors variables, which is an array.
});

app.listen(3000, () => {
  console.log(
    "The server has started on port 3000. Head to localhost:3000 in the browser and see what's there!"
  );
});

To evaluate variables inside of our templates, we will use the Jade #{variable} syntax. When you do string concatenation with Jade - use the ES2015 string templates with the ${javascript to interpolate} syntax. Here is what our index.pug file might look like:

h1 Hello #{name}

And our data.pug - notice we are using the Jade syntax #{} for variables and ES2015 ${} for string concatentation/interpolation.

h1 Here are the colors!
each color in colors
    p #{color}
    a(href=`/colors/${color}`) Learn more about this color

Express and pug

Now in our views/index.pug file let's place the following:

<!DOCTYPE html>
html(lang="en")
head
    meta(charset="UTF-8")
    title Document
body
    h1 "Hello World!"
    p Outer Paragraph
        .foo A div with a class of foo
    h2 Let's do some math! #{5+5}

Template Inheritance with pug

One very useful feature that pug gives us is called template inheritance. What this means is that we can use the same template in all of our files and only have to define it once! We can include templates using the extends keyword. We also need to tell our template where to inject HTML from other files; we do this with the block keyword.

Let's look at an example. In our views folder, let's create a file called base.pug.

<!DOCTYPE html>
html(lang="en")
head
    meta(charset="UTF-8")
    title Document
body
    block content

Next, let's create a hello.pug, extend our base.pug file, and include our own content! We just have to make sure that the content specific to hello.pug is indented inside of block content:

extends base.pug

block content
    h1 Hello World!

For more examples of the features available to you in pug, take a look at the documentation.

css/js using express.static

Before we continue with routing, let's examine how to tell our server how to serve static assets (css/javascript/images). To do this we create a folder called public in the root directory. We can then add the following in our app.js:

const express = require("express");
const app = express();

app.set("view engine", "pug");
app.use(express.static(__dirname + "/public")); // we are using the express.static middleware and specifying a path for static files to be found (__dirname is a variable that we can use to refer to the directory name of the current module)

// even though we were previously using request and response as names of parameters, you will very commonly see these as req and res.
app.get("/", (req, res, next) => {
  return res.render("index");
});

app.listen(3000, () => {
  console.log("Server is listening on port 3000");
});

Example App

You can see an example of this
here.

When you're ready, move on to Lightweight Storage with Redis

Continue

Creative Commons License