Boost your HTML game preprocessing it with Pug.

Overview

Pug is a template engine for Node.js. It acts as a middleman, you write much simpler Pug code, and it compiles it into HTML code that browsers can understand.

Pug can be helpful as we can feed it with reference data, resulting in different HTML. We can make use of conditionals, loops, includes or mixins. Also, Pug supports JavaScript natively, giving us the chance of using JavaScript expressions to format our HTML.

Usage

Basic code

Basically, in Pug you define your tags/elements writing down its name, and indenting its content. Spaces and indentations are, thus, extremely important to get right. This is how you would create a basic HTML5 structure:

  1. Pug
  2. HTML
doctype html
html
    head
    body
<!DOCTYPE html>
<html>
  <head></head>
  <body></body>
</html>

Notice how head and body elements are indented and therefore included inside the html tag.

Language reference

Conditionals

In Pug we can make use of the following operators to check for conditions:

  • if
  • else-if
  • else
  • unless
Parameter Description
if (statement) Evaluates statement to see if it returns true or false. The code nested underneath if will run only if statement returns true.
else if (statement) Chained to an existing if or else if statement; it only runs if the previous statement evaluated to false. The code nested underneath the else if statement will run only if statement evaluates to true.
else The code nested underneath the else statement will run only if all previous statements returned false.
unless (statement) The negation of if (statement) ; the code nested underneath unless will run only if statementreturns false. It is the same as if (!statement)
  1. Pug
  2. HTML
- var test = true
unless (test)
  h1 Test was false
else if (test == 'string')
  h1 Test was a string
else
  h1 Test was true
<h1>Test was true</h1>

Loops

Iterate a number of times over data to create your markup.

Parameter Description
each Evaluates over arrays and objects.
while Evaluates against a condition.
for Evaluates a given number of times.
  1. Pug
  2. HTML
// each loop
ul
  each val in [1, 2, 3, 4, 5]
    li= val

// while loop
- var n = 0;
ul
  while n < 4
    li= n++

// for loop
- var n = 4;
for (let i = 0; i < n; ++i)
  li= i
<!-- each loop-->
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

<!-- while loop-->
<ul>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
</ul>

<!-- for loop-->
<ul>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

Includes

We can include a Pug file inside another. This can be really useful for our Atomic Design approach, mostly with Templates and Pages.

  1. Pug
  2. HTML
doctype html
html
  include includes/head.pug
  body
    h1 My Site
    p Welcome to my super site.

// The contents of includes/head.pug would be:
//
  head
    title My Site
    script(src='/js/main.min.js')
<!DOCTYPE html>
<html>
  <head>
    <title>My Site</title>
    <script src="/js/main.min.js"></script>
  </head>
  <body>
    <h1>My Site</h1>
    <p>Welcome to my super site.</p>
  </body>
</html>

Mixins

Also useful for Atomic Design, but most focused towards Atoms, Molecules and Organisms, we have the mixins: reusable blocks of Pug code.

  1. Pug
  2. HTML
// We define our mixin, that accepts the "name" attribute.
mixin pet(name)
  li.pet= name

//Then, we make use of it in our code
ul
  +pet('cat')
  +pet('dog')
  +pet('pig')
<ul>
  <li class="pet">cat</li>
  <li class="pet">dog</li>
  <li class="pet">pig</li>
</ul>

Template inheritance

We can use Pug's templating capabilities through the use of block and extends keywords.

First, we create a base layout file, in which the bits susceptible to be changed or filled are called block and its contents indented inside. Bear in mind that this can be empty. If filled, it is just with "defaul" content that will be substituted afterwards when the layout gets extended.

html
  head
    title Site's title
    block scripts
      // This is the default content
      script(src='/default.js')
  body
    block content
      // This is empty by default

    footer
      | Site's footer

  1. Pug
  2. HTML
// Here we declare that we are extending the previous file
extends ../v1/04-templates/layout.pug

block scripts
  script(src='/shiny-new-js-that-will-replace-the-layout-one.js')
  script(src='/as-many-stuff-as-you-want.js')

// Here we input the data for each differente page based on the template
block content
  h1 Hello world!
  p Sollicitudin Venenatis Tristique Fermentum Fusce

<!-- The previous Pug code would compile into this HTML -->
<html>
  <head>
    <title>Site's title</title>
    <script src="/shiny-new-js-that-will-replace-the-layout-one.js"></script>
    <script src="/as-many-stuff-as-you-want.js"></script>
  </head>
  <body>
    <h1>Hello world!</h1>
    <p>Sollicitudin Venenatis Tristique Fermentum Fusce</p>
  </body>
</html>

In certain situations, we might want to keep the default contents of the layout, but add more content, we can do so with the append and prepend functions

  1. Pug
  2. HTML
// Here we declare that we are extending the previous file
extends ../v1/04-templates/layout.pug

block append scripts
  script(src='/appended.js')

<!-- The previous Pug code would compile into this HTML -->
<html>
  <head>
    <title>Site's title</title>
    <script src="/default.js"></script>
    <script src="/appended.js"></script>
  </head>
  <body>
  </body>
</html>