Preface

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

Nunjucks is my favorite templating engine. It is powerful. Its syntax is simply a html document, so you can just copy-paste, and change a bit of your code. But I can’t show you the full power here in this article. This article will only provide a simple example for beginner.

Official Documentation

Source Examples

You can obtain source examples here:


1: Nunjucks Case

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

Directory Structure

Consider nunjucks structure.

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

We want the nunjucks to build html artefacts as below:

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

Nunjucks: Example: Tree

Now we can separate each html parts.

Layout

<!DOCTYPE html>
<html lang="en">

<head>
  {% include "partials/head.njk" %}
</head>
<body>
  {% include "partials/sidebar.njk" %}

  <div id="main">
    {% include "partials/navbar.njk" %}

    <div class="w3-container">
    {% block main %}
      <p>Default Page</p>
    {% endblock %}
    </div>
  </div>

</body>
</html>

As shown in order we have three include artefacts.

  • include head.njk,
  • include sidebar.njk,
  • include navbar.njk,

And one block named main.

{% block main %}
  <p>Default Page</p>
{% endblock %}

Nunjucks: ViM NERDTree Panes

It is almost the same with the original head.

  <title>{{ title or "Link Example: Default" }}</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
  <script src="../js/script.js"></script>
  <script src="//localhost:35729/livereload.js"></script>

Here we put the default title if we cannot find title variable.

<title>{{ title or "Link Example: Default" }}</title>

I also add livereload for use with grunt later.

It is a simply a verbatim copy-paste from the original html.

  <div class="w3-sidebar w3-bar-block w3-card w3-animate-left" 
       style="display:none" id="mySidebar">
    <button class="w3-bar-item w3-button w3-large"
       id="closeNav" >Close &times;</button>
    <a class="w3-bar-item w3-button"
       href="index.html">Home</a>
    <a class="w3-bar-item w3-button"
       href="html.html">HTML Link</a>
    <a class="w3-bar-item w3-button"
       href="css.html">CSS Link</a>
    <a class="w3-bar-item w3-button"
       href="php.html">PHP Link</a>
    <a class="w3-bar-item w3-button"
       href="javascript.html">Javascript Link</a>
  </div>

It is also a an exact copy from the original html.

    <div class="w3-teal">
      <button class="w3-button w3-teal w3-xlarge"
              id="openNav">&#9776;</button>
      <div class="w3-container">
        <h1>My Page</h1>
      </div>
    </div>

    <div class="w3-bar w3-black">
      <a class="w3-bar-item w3-button"
         href="index.html">Home</a>
      <a class="w3-bar-item w3-button"
         href="html.html">HTML</a>
      <a class="w3-bar-item w3-button"
         href="css.html" >CSS</a>
      <a class="w3-bar-item w3-button"
         href="php.html" >PHP</a>
      <a class="w3-bar-item w3-button"
         href="javascript.html">Javascript</a>
    </div>

Index

By extending the partials/layout.njk, we can alter the content of main block, and also setup the title variable.

{% extends "partials/layout.njk" %}

{% set title = "Link Example: Home" %}

{% block main %}
  <p>Home Page</p>
{% endblock %}

2: Nunjucks Content Propagation

How does it works ?

Block and Inheritance

In partials/layout.njk we have this block.

{% block main %}
  <p>Default Page</p>
{% endblock %}

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

{% block main %}
  <p>Home Page</p>
{% endblock %}

Title

Variable Propagation Between Template

In index.njk we have this variable.

{% set title = "Link Example: Home" %}

This variable will be utilized in partials/head.njk

<title>{{ title or "Link Example: Default" }}</title>

This is almost self explanatory.

Main Files

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

{% extends "partials/layout.njk" %}

{% set title = "Link Example: CSS" %}

{% block main %}
  <p>CSS Page</p>
{% endblock %}
{% extends "partials/layout.njk" %}

{% set title = "Link Example: PHP" %}

{% block main %}
  <p>PHP Page</p>
{% endblock %}

Result

Conclusively, we can check the result in build/index.html, against the original html.

<!DOCTYPE html>
<html lang="en">

<head>
  
  <title>Link Example: Home</title>
  ...
</head>
<body>
  ...

  <div id="main">
    ...
    <div class="w3-container">
      <p>Home Page</p>
    </div>
  </div>

</body>
</html>

3: Grunt Configuration

Command Line Interface

I cannot figure out how to use nunjucks-cli properly. Luckily, we have this good grunt, as replacement.

package.json

All you need to know is the devDependencies.

  "devDependencies": {
    "grunt": "^1.0.1",
    "grunt-contrib-watch": "^1.1.0",
    "grunt-nunjucks-2-html": "^2.2.0",
    "nunjucks": "^3.2.1"
  }

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 = {

    nunjucks: {
      options: {
        data:  grunt.file.readJSON('data.json'),
        paths: 'views'
      },
      render: {
        files: [ {
          cwd: "views",
          src: "*.njk",
          dest: "build",
          expand: true,
          ext: ".html"
        } ]
      }
    },

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

  };

  grunt.initConfig(config);

  // load the tasks
  grunt.loadNpmTasks('grunt-nunjucks-2-html');
  grunt.loadNpmTasks('grunt-contrib-watch');

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

};

The configuration is self explanatory. Just read the official documentation of grunt-nunjucks-2-html.

Data

We can skip data in grunt, and your build will be working just fine. But just in case you need to surpress warning message, you can put empty data.json as below:

{
}

Running Grunt

Nunjucks: Grunt: Watch

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


What’s Next?

We still have two grunt example: EJSandhandlebars`.

Consider continue reading [ Template - Grunt - EJS ].