Introducing Project Orca - Part 3

January 18, 2019

In Introducing Project Orca - Part 1 I wrote about when to use a static website and provided a short overview of what a Metalsmith static site generator is. In Introducing Project Orca - Part 2 I described how Metalsmith works.

In this blogpost I will briefly introduce the templating engine that was used in Project ORCA

I wanted to use a templating engine that is Javascript based and supports a Twig like syntax and found Nunjucks. Both engines have a common ancestor, Jinja, which was modeled after Django’s templates. (Django is a high-level Python Web framework). Nunjucks is maintained by Mozilla.

Nunjucks is a token based templating system with support for variables, loops and conditionals, in addition it also supports advanced page composition with block inheritance, includes, layout inheritance, custom tags and macros. The Nunjucks docs can be found here.

Here is an example of a Nunjucks template:



<!doctype html>
<html lang="en" itemscope="" itemtype="”http://schema.org/Article”">
    <head>
        {% include "head.html" %}
    </head>

    <body id="onTop" class="{{ body_classes }} isLoading">
        {% include "browser-upgrade.html" %}

        <div class="container">
            <div class="has-columns cf">
                <section class="main">
                    {% if title %}
                        <h1 class="page-title">{{ title }}</h1>
                    {% endif %}
				<ul class="blog-list-vertical list-unstyled">
                    {% for blogpost in pagination.files %}            
                        <li class="cf">
                            <a href="/{{ blogpost.path | makePermalink }}">
                                <div class="blog-list-vertical__img" style="background-image: url({{ blogpost.tn }})"></div>
                            </a>
                            <div class="blog-info">
                                <a href="/{{ blogpost.path | makePermalink }}"><h2>{{ blogpost.title }}</h2></a>
                                <p>
                                    by {% for index, author in blogpost.blogAuthors %}{{ author.title }}{% if not loop.last %}, {% endif %}{% endfor %}
                                    <br>on {{ blogpost.date | dateFilter("MMMM D, YYYY") }}
                                </p>
                            </div>
                        </li>       
                    {% endfor %}
                    </ul>

                    {% include "pager.html" %}

                </section>
                <aside class="sidebar">
                    <h3>Blog Categories:</h3>
                    {% include "categories-list.html" %}

                    <h3>Tags</h3>
                    {% include "tags-list.html" %}

                    <h3>Featured Posts</h3>
                    <ul class="blog-list-overview">
                        {% for featuredBlogPost in featuredBlogPosts %}
                        <li>
                            <ul class="list-unstyled">
                            <li class="blog-post-title"><a href="/{{ featuredBlogPost.path }}/">{{ featuredBlogPost.title }}</a></li>
                            <li><a class="read-more-link" href="/{{ featuredBlogPost.path }}/">Read it <span>»</span></a></li>
                            </ul>
                        </li>
                        {% endfor %}
                    </ul>
                </aside>
            </div>
        </div>

    {% block footer %}
        {% include "footer.html" %}
    {% endblock %}

    <a id="toTopButton" href="#onTop"><i class="icon icon-arrow-up"></i></a>
    
    {% block body_scripts %}
        {% include "scripts.html" %}
    {% endblock %}

  </body>
</html>

This example uses various features of Nunjucks and many act very similar to their Javascript cousins./p>

Variables

This example shows a variable body_classes being added to a static class isLoading.



<body id="onTop" class="{{ body_classes }} isLoading"> ... </body>

include

include imports other templates in place. This allows the use of common page elements. For example:



<head>
    {% include "head.html" %}
</head>

if

if allows conditional rendering like the example below:



{% if title %}
    <h1 class="page-title">{{ title }}</h1>
{% endif %}

for

for allows us to iterate over arrays and objects. In the example below I create all list items by iterating over an object called featuredBlogPosts.



<ul class="blog-list-overview">
    {% for featuredBlogPost in featuredBlogPosts %}
    <li>
        <ul class="list-unstyled">
        <li class="blog-post-title"><a href="/{{ featuredBlogPost.path }}/">{{ featuredBlogPost.title }}</a></li>
        <li><a class="read-more-link" href="/{{ featuredBlogPost.path }}/">Read it <span>»</span></a></li>
        </ul>
    </li>
    {% endfor %}
</ul>

Filters

From the Nunjucks Docs: "Filters are essentially functions that can be applied to variables. They are called with a pipe operator (|) and can take arguments.". In the example below the path to a blogpost is transformed into a permalink with the filter function makePermalink



<a href="/{{ blogpost.path | makePermalink }}"><h2>{{ blogpost.title }}</h2></a>

Template Inheritance

Again from the Nunjucks docs: "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.". In this example I define a block footer and then include footer.html. Any template that extends this template can now add to or replace the content of this block.



{% block footer %}
    {% include "footer.html" %}
{% endblock %}

The full Nunjucks docs can be found here. I'd also recommend reading Building A Static Site With Components Using Nunjucks by Chris Coyier on the Smashing Magazine website for his take on how to use Nunjucks.