ssg  
Where to Discuss?

Local Group

Preface

Goal: Configure most common settings.

This chapter will introduce common basic configuration, that required to make a simple site.

Source Code

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

Layout Preview for Tutor 03

Nunjucks: Layout Preview for Tutor 03


1: Layout Alias

Issue

Remember this frontmatter below:

---
layout    : layouts/post
title     : Every Day
---

For a real world site that grow to hundred of pages, it would be nice if we can write the layout, without worry about which directory this layout comes from.

.eleventy.js

We can utilize addLayoutAlias in configuration.

module.exports = function(eleventyConfig) {
  ...

  // Layout Alias
  eleventyConfig.addLayoutAlias("home",     "layouts/home.njk");
  eleventyConfig.addLayoutAlias("page",     "layouts/page.njk");
  eleventyConfig.addLayoutAlias("post",     "layouts/post.njk");
  eleventyConfig.addLayoutAlias("archive",  "layouts/archive.njk");
  eleventyConfig.addLayoutAlias("tags",     "layouts/tags.njk");
  eleventyConfig.addLayoutAlias("tag-name", "layouts/tag-name.njk");
  
  ...
};

11ty: Layout Alias in Eleventy Configuration

Layout as Page Kind

Now we can rewrite the layout shorter.

---
layout    : post
title     : Every Day
---

This way, we can rename layout directory and change the configuration, without touching any post content.

It is also easier to remember layout as page kind. We can say that this content wear post layout.


2: Data: Title

As common in SSG, eleventy also suppport data.

.eleventy.js

We have to change the configuration a bit.

module.exports = function(eleventyConfig) {
  // Return your Config object
  return {
    ...

    // Directory Management
    dir: {
      input: "views",
      output: "dist",
      // ⚠️ These values are both relative to your input directory.
      includes: "_includes",
      data: "_data"
    }
  };
};

Data: Introducing Metadata

Separate Data from Configuration

Most common data is, of course the site metadata, such as default site title and so on.

module.exports = {
  "title": "Your mission. Good Luck!"
};

Why would I need another configuration file? Well, configuration tends to grow. At first it makes sense to put, the whole thing in configuration file, just like any other SSG does. After sometimes, you have a bunch of metadata, and it is got harder to differ which one is configuration, and which one is custom user data. So here it is, from the very start, we put all data somewhere elese outside the .eleventy.js.

Layout: Nunjucks Head

Now you can change your old head.njk

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

To this below

  <title>{{ title or metadata.title }}</title>

3: Assets: Pass Through Copy

We all love static assets, from stylesheet, font, javascript, and favicon.

.eleventy.js

Eleventy copy static assets, to output directory such as dist or _site using this configuration:

module.exports = function(eleventyConfig) {

  // Directory Management
  eleventyConfig.addPassthroughCopy("assets");

  ...

  // Return your Config object
  return {
    ...

    // Directory Management
    passthroughFileCopy: true,    
    dir: {
      ...
      output: "dist",
      ...
    }
  };
};

You can read in 11ty official documentation.

What’s New Here

The first line contain which directory will copied.

  eleventyConfig.addPassthroughCopy("assets");

The second line, is just a flag, whether you enable it, or not.

    passthroughFileCopy: true,

Asset Example

Now you can check in directory tree, where the favicon copied.

.
├── assets
│   └── favicon.ico
├── dist
│   ├── assets
│   │   └── favicon.ico
│   ├── index.html
│   └── pages
│       ├── about
│       │   └── index.html
│       └── index.html
└── views

Partial: Nunjucks Head

Now you can add favicon in head.njk.

  <title>{{ title or metadata.title }}</title>
  <link href="/assets/favicon.ico"
        rel="shortcut icon" type="image/x-icon" />

4: Filter: MomentJS

Don’t you want to show proper date in your post? There are some javascript libraries capable to do this. One of them is moment library.

Official Site

Reference

This eleventy filter is verbatim copy of code from this article.

package.json

You should install the moment library first.

  "devDependencies": {
    "@11ty/eleventy": "^0.10.0",
    "moment": "^2.24.0"
  }

.eleventy.js

Consider create a filter named date using addNunjucksFilter.

const moment = require("moment");

module.exports = function(eleventyConfig) {
  ...
  
  // Copy paste from Jérôme Coupé
  eleventyConfig.addNunjucksFilter("date", function(date, format) {
    return moment(date).format(format);
  });

  ...
};

Using Date Filter

Now you can use date filter in post layout:

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

{% block main %}
  <h2>{{ title or metadata.title }}</h2>
  <pre>{{ page.date | date('MMMM Do, YYYY') }}</pre>
  <br/>

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

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

5: URL: Post Permalink

Furthermore we can utilize this moment js to manage post permalink.

Reference

Page Content: every-day.md

---
layout    : post
title     : Every Day
date      : 2015-10-03 08:08:15
slug      : every-day
permalink : "/{{ date | date('YYYY/MM/DD') }}/{{ slug }}/index.html"
---

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

I mean, really, truly,
imagine it.

Have a look at this line in frontmatter:

permalink : "/{{ date | date('YYYY/MM/DD') }}/{{ slug }}/index.html"

This will be rendered as:

  • dist/2015/10/03/every-day/index.html

.eleventy.js

Since you content is written in markdown format, you need to enable nunjucks in configuration.

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

Directory Tree: Output

Check and recheck, as always.

$ tree dist
dist
├── 2015
│   └── 10
│       └── 03
│           └── every-day
│               └── index.html
├── assets
│   └── favicon.ico
├── index.html
└── pages
    ├── about
    │   └── index.html
    └── index.html

7 directories, 5 files

11ty: Tree: dist


6: Config Object

The style of writing configration is different for each coder. I’d rather separate stuff, such as Config object. So instead of writing like this below:

module.exports = function(eleventyConfig) {

  ...

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

I write the config as below:

// Put main config above
// to avoid distraction from complex configuration
const config = {
  // URL Related
  pathPrefix: "/",
  ...
};

module.exports = function(eleventyConfig) {

  ...

  // Return your Config object
  return config;
};

11ty: Configuration Object in .eleventy.js

I like to put the main configuration on top. Because the other part tends to get longer as the site grow. I will use this style, starting in the next configuration.


What is Next ?

Consider continue reading [ Eleventy - Collections ]. Still minimalist with pure HTML without any stylesheet. We are going to go deep, examine collections in eleventy.

Thank you for reading.