ssg  
Where to Discuss?

Local Group

Preface

Goal: Getting started with layout using Nunjucks templating engine.

Layout enable you to create many kind of page template, such as page kind, post kind, landing page (home kind), or archive page.

Source Code

This article use tutor-02 theme. We will create it step by step.

Official Site.

Layout Preview for Tutor 02

Nunjucks: Layout Preview for Tutor 02


0: Theme Making

Consider to have a look at the big picture below:

SSG Illustration: Theme Making


1: Configuration

Consider go straight away to templating engine called nunjucks. In order to use nunjucks, we need to alter the configuration a bit.

.eleventy.js

module.exports = function(eleventyConfig) {

  // Return your Config object
  return {
    // URL Related
    pathPrefix: "/",

    // Templating Engine
    templateFormats: [
      "md",
      "njk",
      "html"
    ],

    markdownTemplateEngine: false,
    htmlTemplateEngine: "njk",
    dataTemplateEngine: false,

    // Directory Management
    dir: {
      // default
      input: "views",
      output: "_site",
      // ⚠️ This value is relative to your input directory.
      includes: "_includes",
    }
  };
};

What’s New Here?

  1. Utilize markdown as an article
    templateFormats: [
      "md",
      "njk",
      "html"
    ],
  1. Treat pages/archive.html as a nunjucks template.
    markdownTemplateEngine: false,
    htmlTemplateEngine: "njk",
    dataTemplateEngine: false,

2: Refactor

Directory Tree: Includes

Consider create each artefacts manually.

$ tree views/_includes
views/_includes
├── layouts
│   ├── base.njk
│   ├── page.njk
│   └── post.njk
└── site
    ├── footer.njk
    ├── header.njk
    └── head.njk

2 directories, 6 files

11ty: Tree: Views: Includes

Layout: Nunjucks Base

Instead of put everything in one html file, we can separate each html part in different nunjucks file, and call them using include.

<html>
<head>
  {% include "site/head.njk" %}
</head>
<body>
  {% include "site/header.njk" %}
  <main role="main">
    {% block main %}{% endblock %}
  </main>
  {% include "site/footer.njk" %}
</body>
</html>

And three includes:

  • head,

  • header,

  • footer.

We are going to replace {% block main %}{% endblock %}, in both page.njk and post.njk.

Partial: Nunjucks Head

We can use default title, if there is no title available, in frontmatter.

  <title>{{ title or "Your mission. Good Luck!" }}</title>

Partial: Nunjucks Header

<blockquote>
  <i>Your mission, should you decide to accept it.</i>
</blockquote>
<blockquote>
  <i>As always, should you be caught or killed,
  any knowledge of your actions will be disavowed.</i>
</blockquote>

Layout: Nunjucks Page

Template inheritance in nunjucks, start with the word extends.

{% extends "layouts/base.njk" %}

{% block main %}
  <h2>{{ title }}</h2>
  <strong>This is a page kind layout.</strong>
  <br/>

  {{ content | safe }}
{% endblock %}

Layout: Nunjucks Post

Template inheritance in nunjucks, start with the word extends.

{% extends "layouts/base.njk" %}

{% block main %}
  <h2>{{ title }}</h2>
  <pre>{{ page.date }}</pre>
  <br/>

  <strong>This is a post kind layout.</strong>
  <br/>

  {{ content | safe }}
{% endblock %}

I add {{ page.date }} to differ post kind and page kind.

Finally

We are done with simple refactoring. These simple snippets, show how nunjucks works. Especially template inheritance.

11ty: Layout Panes: Nunjucks Refactor


3: Pages and Posts

We are freely to make any kind of pages. Here we make two common blog page kind:

  • Page Kind

  • Post Kind

Remember, that in configuration, every html file is actually using nunjucks template engine.

Directory Tree: Includes

Consider create each artefacts manually.

$ tree views/ -I '_includes'
views/
├── index.html
├── pages
│   ├── about.md
│   └── archive.html
└── posts
    └── every-day.md

2 directories, 4 files

11ty: Tree: Views: Contents

Page Content: index

It is actually very similar with previous index.html.

---
layout    : layouts/page
eleventyExcludeFromCollections: true
---

  <p>To have, to hold, to love,
  cherish, honor, and protect?</p>
  
  <p>To shield from terrors known and unknown?
  To lie, to deceive?</p>

  <p>To live a double life,
  to fail to prevent her abduction,
  erase her identity, 
  force her into hiding,
  take away all she has known.</p>

11ty: Preview in Browser

What’s new here is, we don’t want this page to be included in collections.

eleventyExcludeFromCollections: true

Page Content: pages/about

This is a markdown file artefact, with frontmatter.

---
layout    : layouts/page
title     : About Rescue Mission
---
This was not a rescue mission!

Let me put to you like this.
If the secretary wanted me out of there,
then things are really bad out here.

11ty: Page Content: pages/about

Page Content: pages/archive

It is clear that this one is using nunjucks template engine. With permalink in frontmatter, you can render the page, from view/pages/archive.html to _site/pages/index.html

---
layout    : layouts/page
title     : Archive
permalink : /pages/
eleventyExcludeFromCollections: true
---

  <ul>
    {%- for post in collections.all | reverse -%}
    <li>
      <a href="{{ post.url | url }}">
        {{ post.data.title }}</a>
    </li>
    {%- endfor -%}
  </ul>

11ty: Page Content: pages/archive

Pay attention to the loop.

    {% for post in collections.all %}
      ...
    {% endfor %}

You can try to set eleventyExcludeFromCollections: false, and see what’s happened.

Post Content: posts/every-day

And this one has some more information in frontmatter.

---
layout    : layouts/post
title     : Every Day
date      : 2015-10-03 08:08:15
slug      : every-day
tags      : ['subtitle', 'story']
---

I've been thinking about this
over and over and over.
<!-- more --> 

I mean, really, truly,
imagine it.

11ty: Post Content: posts/every-day

Local Render

You might want to see how it works by looking at the _site directory.

$ tree _site
_site
├── index.html
├── pages
│   ├── about
│   │   └── index.html
│   └── index.html
└── posts
    └── every-day
        └── index.html

4 directories, 4 files

11ty: Tree: _site

What’s in your browser is what rendered in _site.


4: Default Variable

We can set variable in frontmatter, and in content. But you need to be aware of the differences between this two method.

Layout: Nunjucks Color

Consider this example layout below:

<html>
<head>
  {% include "site/head.njk" %}
</head>
<body>
  {# use default unless available #}
  {% set color = color or 'brown' %}
  
  <main role="main">
    <p><i>This is a variable propagation test.</i></p>
    {{ content | safe }}
    <p>In this layout, color is <b>{{ color }}</b>.</p>
  </main>
</body>
</html>

This layout will read color variable from page, or using brown color as default, if it cannot find any color.

  {% set color = color or 'brown' %}

Page Content: pages/color-test-01

This page set color in frontmatter.

---
layout    : layouts/color
title     : Test Color in Frontmatter
eleventyExcludeFromCollections: true
color     : red
---

<p>In this content, color is <b>{{ color }}</b>.</p>

11ty: Nunjuck: Variable in Frontmatter

Page Content: pages/color-test-02

This page set color in frontmatter.

---
layout    : layouts/color
title     : Test Color in Content
eleventyExcludeFromCollections: true
---

{% set color = 'indigo' %}
<p>In this content, color is <b>{{ color }}</b>.</p>

11ty: Nunjuck: Variable in Content

Both method have different result.

As you can see, both have different result. This difference behavior in nunjucks has advantage, that you can choose, whether you want the layout and content, has the same color, or different color. We will explore this advantage later.


What is Next ?

Consider continue reading [ Eleventy - Configuration ]. Still with pure HTML without any stylesheet. We are going to add most common configuration, that required to make a simple site.

Thank you for reading.