Nunjucks: A JavaScript Template Engine

Introduction

Templating frameworks separate the layout of dynamic web sites and applications from the logic that integrates with it. All frameworks support various forms of looping, conditional logic and special formatting. But I also wanted an engine that supported advanced page composition elements, to enable me to share layouts across pages, to include blocks of functionality when required, and to generally make it as simple as possible to construct moderately complex page layouts with the minimum of code and as little duplication of effort as possible.

Comparison of template engines

There are a number of popular and capable JavaScript templating engines available, and we looked at several of these:

EJS

EJS (Embedded JavaScript) looks very much like PHP or JSP and is very light on features — far too light to be of any use. Immediately discarded.

Jade

The most obvious feature of Jade is that it uses a whitespace-based notation with no brackets (like Coffeescript) which is therefore either fabulous (if you like that sort of thing) or a completely horrendous showstopper if you don’t (and I didn’t). Feature-wise it’s on a par with most of the other engines, but the styling made it an almost immediate no-no.

Mustache / Handlebars

Uses a familiar {{ token system }} to embed logic into existing templates (and not just HTML). Provides good looping, logic and variables support. Poor support, however, for partials and blocks and other elements that make it easy to compose moderately complex page structures, which is a key requirement for even the simple CMS I was aiming to create. Next…

Dust

Currently popular due to its adoption by LinkedIn. On the face of it, looks fairly similar to Mustache / Handlebars but with useful additional features like named blocks. However the template loading and rendering process is rather clunky and it still doesn’t support a particularly wide range of page construction features. Good, but not good enough…

Nunjucks

Another {{ token based system }} with all of the logic, looping and variable control that other engines provide. But in addition it supports some more advanced page composition elements e.g. block inheritance, includes, layout inheritance, custom tags and macros — all absolutely perfect for a CMS where pages are typically composed of a series of “building blocks”. We have a winner!

References

Some useful resources for comparing templating engines:

Basic rendering examples

Let’s see some examples of Nunjucks in action…

Runtime rendering in Node using nunjucks.render

Firstly we’ll look at an example where we’re using Nunjucks to render a page in response to a web service request being handled by a Node server — so a very similar scenario to what happens when you request a PHP or ColdFusion or ASP .NET page in a traditional website or web application.

We assume that Node is already installed.

Install Express and Nunjucks:

npm install express --save
npm install nunjucks --save

Create our basic app.js structure:

var express = require( 'express' ) ;
var nunjucks = require( 'nunjucks' ) ;
var app = express() ;

Configure Nunjucks:

var PATH_TO_TEMPLATES = '.' ;
nunjucks.configure( PATH_TO_TEMPLATES, {
autoescape: true,
express: app
} ) ;

Simple route:

app.get( '/home.html', function( req, res ) {
return res.render( 'index.html' ) ;
} ) ;
app.listen( 3000 ) ;

Create template index.html:

<p>Hello World</p>

Run with:

node app.js

and browse to http://localhost:3000. Woo!

Adding runtime data

Let’s extend this example quickly to illustrate how you can pass data to your Nunjucks template…

Firstly, let’s pass some data to the render function:

app.get( '/home.html', function( req, res ) {
var data = {
firstName: 'Andy',
lastName: 'Neale'
} ;
return res.render( 'index.html', data ) ;
} ) ;

Secondly, we’ll reference this data in our index.html template:

<p>Hello {{ data.firstName }}</p>

You can probably guess what’s going to happen when we browse to http://localhost:3000...

Pre-compilation using Gulp

If you have templates that don’t rely on runtime data, then an alternative to rendering them on demand is to use Gulp (or Grunt, if that’s your cup of tea) to precompile them at build time.

So let’s say you have a simple site consisting of two pages with a common layout:

  • src/index.html
  • src/contact-us.html
  • src/_layout.html

So your pages might look like this:

index.html

{% set title = 'Home' %}
{% extends '_layout.html' %}
{% block content %}
<h1>Welcome</h1>
<p>Isn't this just the most exciting website ever?</p>
{% endblock %}

contact-us.html

{% set title = 'Contact Us' %}
{% extends '_layout.html' %}
{% block content %}
<h1>Contact Us</h1>
<p>Call us on 0800 000 0000 or email us at <a href="mailto:nobody@nowhere.com?subject=Nothing">nobody@nowhere.com</a>.</p>
{% endblock %}

_layout.html

<!DOCTYPE>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

Install the gulp-nunjucks plugin:

npm install gulp-nunjucks --save

Create a simple gulpfile.js in your root project folder:

var gulp = require( 'gulp' ) ;
var nunjucks = require( 'nunjucks' ) ;
var COMPILE = {
SRC: '/src/**.html',
DEST: '/dist’
} ;
gulp.task( 'render', function() {
return gulp.src( COMPILE.SRC )
.pipe( nunjucks() )
.pipe( gulp.dest( COMPILE.DEST ) ) ;
} ) ;

Run the rendering process:

gulp render

The resulting generated HTML pages would look like this:

index.html

<!DOCTYPE>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome</h1>
<p>Isn't this just the most exciting website ever?</p>
</body>
</html>

contact-us.html

<!DOCTYPE>
<html>
<head>
<title>Contact Us</title>
</head>
<body>
<h1>Contact Us</h1>
<p>Call us on 0800 000 0000 or email us at <a href="mailto:nobody@nowhere.com?subject=Nothing">nobody@nowhere.com</a>.</p>
</body>
</html>

Nunjucks features

Full documentation can be found here:

https://mozilla.github.io/nunjucks/templating.html

In this section we’ll cover some of the basics just to illustrate some of Nunjucks’ key features…

Template inheritance

Template inheritance is a way to make it easy to reuse templates. When writing a template, you can define “blocks” that child templates can override. (This is what we did above with the {% block content %} section.)

In this way, the child template can inherit from a base template and also populate multiple, discrete blocks in that template. In fact the “inheritance chain” can be as long as you like, so for example an individual news item on a web page might inherit a “news story” template (and other pages might have other templates e.g. “blog article”, “photo gallery”) which might in turn inherit a core base template which contains items common to all pages.

Includes

The opposite of extends, these include a template inside the current template. This is useful for pulling in blocks of content that are used in multiple places across the site or application.

Import and macros

Import lets you load a template and access any variables and macros (functions) defined in it. This can be useful for things like creating functions to render form fields in a consistent fashion… a bit like writing custom tags in ColdFusion, for example. Let’s illustrate that — we’ll start with a template call forms.html which looks like this:

{% macro field( name, value = '', type = 'text' ) %}
<div class="field">
<input type="{{ type }}" name="{{ name }}" value="{{ value | escape }}" />
</div>
{% endmacro %}
{% macro label( text ) %}
<div>
<label>{{ text }}</label>
</div>
{% endmacro %}

We can import this template and use it to quickly render a series of form fields:

{% import "forms.html" as forms %}
{{ forms.label( 'Username' ) }}
{{ forms.field( 'user' ) }}
{{ forms.label( 'Password' ) }}
{{ forms.field( 'pass', type = 'password' ) }}

This is particularly useful when using a framework like Foundation or Bootstrap which require a reasonable amount of surrounding HTML / CSS — if you’ve got this being rendered in a macro, your template code becomes much simpler. (Plus if your template is doing all of its rendering via macros, it isn’t directly coupled to the framework in question, which makes it easier to switch frameworks, or to make changes that are common to all form fields of a particular type.)

Logic — If / For / While

if tests a condition and is used to selectively display content or to perform other operations:

{% if variable %}
Variable exists, hurrah
{% endif %}
{% if user.authorised %}
{% extends "logged-in.html" %}
{% else %}
{% extends "logged-out.html" %}
{% endif %}

for loops over arrays:

code

var messages = [ 'Email address must be entered', 'Password must be at least eight characters long' ] ;

template

<div class="wrapper">
<div id="message_area">
<div class="messages status">
{% for message in messages %}
{{ message }}<br />
{% endfor %}
</div>
</div>
</div>

Next steps

Read the official Nunjucks documentation to get a clearer picture of its features and capabilities.

In future posts I’ll be showing how we combined the templating facilities of Nunjucks with the Wintersmith static site generator to build our own simple multi-lingual CMS…