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.

npm install express --save
npm install nunjucks --save
var express = require( 'express' ) ;
var nunjucks = require( 'nunjucks' ) ;
var app = express() ;
var PATH_TO_TEMPLATES = '.' ;
nunjucks.configure( PATH_TO_TEMPLATES, {
autoescape: true,
express: app
} ) ;
app.get( '/home.html', function( req, res ) {
return res.render( 'index.html' ) ;
} ) ;
app.listen( 3000 ) ;
<p>Hello World</p>
node app.js

Adding runtime data

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

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

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.

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

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>
npm install gulp-nunjucks --save
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 ) ) ;
} ) ;
gulp render

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:

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.)

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 %}
{% import "forms.html" as forms %}{{ forms.label( 'Username' ) }}
{{ forms.field( 'user' ) }}
{{ forms.label( 'Password' ) }}
{{ forms.field( 'pass', type = 'password' ) }}

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 %}

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.

Web developer. Currently building web apps in React. Also known to use Node, jQuery, Foundation and more. Frequently covered in cats.

Web developer. Currently building web apps in React. Also known to use Node, jQuery, Foundation and more. Frequently covered in cats.