Preface

Goal: Build static HTML files using partial Pug utilizing Grunt.

pug is good for beginner who want to step into templating engine.

  • First the indented looks, that is entirely different with html.

  • Second, it just works with Command Line Interface. No need third party tools such as grunt or gulp.

Unfortunately, not all html processor as easy as pug. So for the rest of the chapter here, we are going to build html using grunt.

Official Documentation

Pug With Grunt

I have already wrote an article about pug here:

Along with an example of how to build grunt.

Source Examples

You can obtain source examples here:


1: Pug Case

We use pug as html preprocessor to build html documents. Consider transform our last HTML Case into Pug Case.

Install

$ npm i -g pug-cli

Directory Structure

Consider pug structure.

└── views
    ├── css.pug
    ├── html.pug
    ├── index.pug
    ├── javascript.pug
    ├── partials
    │   ├── head.pug
    │   ├── layout.pug
    │   ├── navbar.pug
    │   └── sidebar.pug
    └── php.pug

We want the pug to build html artefacts as below:

└── build
    ├── css.html
    ├── html.html
    ├── index.html
    ├── javascript.html
    └── php.html

Pug: Example: Tree

Now we can separate each html parts.

Layout

doctype html
html(lang="en")

- var title = "Link Example: Default"

  head
    include head.pug
  body
    include sidebar.pug

    #main
      include navbar.pug
      .w3-container
        block content
          p Default Page

As shown in order we have three include artefacts.

  • include head.pug,
  • include sidebar.pug,
  • include navbar.pug,

One variable named title,

- var title = "Link Example: Default"

And one block named content.

block content
  p Default Page

Jade/Pug: ViM NERDTree Panes

It is a simple pug translation.

meta(charset='utf-8')
block title
  title= title
meta(name='viewport', content="width=device-width, initial-scale=1")
link(href='https://www.w3schools.com/w3css/4/w3.css', rel='stylesheet', type='text/css')
script(src='../js/script.js')
script(src='//localhost:35729/livereload.js')

Here we put the title variable inside a block named title.

block title
  title= title

I also add livereload for use with grunt later.

It is simply a html tag in pug. Nothing special.

#mySidebar.w3-sidebar.w3-bar-block.w3-card.w3-animate-left(style='display:none')
  button#closeNav.w3-bar-item.w3-button.w3-large 
    | Close ×
  a.w3-bar-item.w3-button(href='index.html')
    | Home
  a.w3-bar-item.w3-button(href='html.html')
    | HTML Link
  a.w3-bar-item.w3-button(href='css.html')
    | CSS Link
  a.w3-bar-item.w3-button(href='php.html')
    | PHP Link
  a.w3-bar-item.w3-button(href='javascript.html')
    | Javascript Link

It is also simply a html tag in pug. Nothing special either.

.w3-teal
  button#openNav.w3-button.w3-teal.w3-xlarge
    | ☰
  .w3-container
    h1 My Page
.w3-bar.w3-black
  a.w3-bar-item.w3-button.w3-large(href='index.html')
    | Home
  a.w3-bar-item.w3-button.w3-large(href='html.html')
    | HTML
  a.w3-bar-item.w3-button.w3-large(href='css.html')
    | CSS
  a.w3-bar-item.w3-button.w3-large(href='php.html')
    | PHP
  a.w3-bar-item.w3-button.w3-large(href='javascript.html')
    | Javascript

Index

By extending the partials/layout.pug, we can alter the content of each block: title and content.

extends partials/layout.pug

block title
  title Link Example: Home

block content
  p Home Page

2: Pug Content Propagation

How does it works ?

Block and Inheritance

In partials/layout.pug we have this block.

    #main
      include navbar.pug
      .w3-container
        block content
          p Default Page

Then we can replace the content, of the block in child layout index.pug.

extends partials/layout.pug

block content
  p Home Page

Title: Using Variable

Variable Propagation Between Template

In partials/layout.pug we have this variable.

- var title = "Link Example: Default"

This should work perfectly with include partials/head.pug

  title= title

But unfortunately, pug cannot have variable, in top level of extended files. This means we cannot alter the default variable.

Title: Using Block

The solution is to wrapped the content in block instead.

As in index.pug below:

block title
  title Link Example: Home

The partials/head.pug would be

block title
  title Link Example: Default

Or if you wish to use default variable.

block title
  title =title

Where the title variable comes from partials/layout.pug.

Main Files

This time, all the main files can be so short as below:

extends partials/layout.pug

block title
  title Link Example: CSS

block content
  p CSS Page
extends partials/layout.pug

block title
  title Link Example: PHP

block content
  p PHP Page

Result

Finally we can check if the result is right in build/index.html.

<!DOCTYPE html>
<html lang="en"></html>
<head>
  <meta charset="utf-8">
  <title>Link Example: Home</title>
  ...
</head>
<body>
  ...
  <div id="main">
    ...
    <div class="w3-container">
      <p>Home Page</p>
    </div>
  </div>
</body>

3: Grunt Configuration

Command Line Interface

Without grunt, you can run pug in command line interface.

$ cd views
$ pug -w -P -p . -o ../build *.pug
  • .

Now consider discuss this grunt stuff.

package.json

All you need to know is the devDependencies.

  "devDependencies": {
    "grunt": "^1.0.1",
    "grunt-contrib-pug": "^2.0.0",
    "grunt-contrib-watch": "^1.1.0",
    "pug": "^2.0.4"
  }

To begin with grunt, you need to run npm install first.

Gruntfile.js

You also need to a configuration file named Gruntfile.js.

module.exports = function(grunt) {
  // configure the tasks
  let config = {

    pug: {
      compile: {
        options: {
          data: {
            debug: false
          },
          pretty: true
        },
        files: [ {
          cwd: "views",
          src: "*.pug",
          dest: "build",
          expand: true,
          ext: ".html"
        } ]
      }
    },

    watch: {
      pug: {
        files: ['views/**/*'],
        tasks: ['pug'],
        options: {
          livereload: true,
          interrupt: false,
          spawn: false
        }
      }
    }

  };

  grunt.initConfig(config);

  // load the tasks
  grunt.loadNpmTasks('grunt-contrib-pug');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // define the tasks
  grunt.registerTask('default', [
    'pug', 'watch'
  ] );

};

The configuration is self explanatory. Just read the official documentation of grunt-contrib-pug.

Running Grunt

Pug: Grunt: Watch

Now you can build your own static html files using pug.


What’s Next?

We still have three grunt example: nunjucks, EJS and handlebars.

Consider continue reading [ Template - Grunt - Nunjucks ].