はじめに
前回の記事で 11ty/eleventy(以下、11ty) の公式スタートガイドに則ってサンプルを作成してみました。
HTML テンプレートエンジン詰め合わせ 11ty/eleventy を使ってみる
上記の記事で紹介した内容は、スタートガイドによるファイル生成と front-matter を使用した機能のごく一部です。11ty の機能をさらに詳しく確認していくことが本記事の目的になります。
記事の概要
公式の スタータープロジェクト として、eleventy-base-blog というリポジトリが公開されています。
サンプルページはこちら。
11ty を使用してブログコンテンツを含む静的サイトを構築する、というテンプレートページになっていますので、このページのソースを眺めつつ 11ty でできることを確認していきます。
前回記事で記述していますが、 11ty には CSS や JS ファイル周りのコンパイル/トランスパイルは含まれておらず、今回取り扱う eleventy-base-blog に関しても CSS, JS のコンパイル/トランスパイル環境は含まれていません。
CSS, JS の環境構築については後ほど別記事で記載予定です。
2020.04.18
11ty/eleventy で CSS / SCSS を扱うために
を追加しました。
ディレクトリ構成
HTML ファイルを生成する .njk
ファイルと .md
ファイル、.json
ファイルを中心にファイルを確認します。
eleventy-base-blog/
├ _site/
├ package.json
├ .eleventy.js
├ _data/
| └ metadata.json
├ _includes/
| └ layouts/
| └ base.njk
| └ home.njk
| └ post.njk
| └ postslist.njk
├ index.njk
├ sample.njk (記事の都合上追加)
├ page-list.njk
├ archive.njk
├ tags.njk
├ tags-list.njk
├ 404.md
├ about/
| └ index.md
├ posts/
| └ posts.json
| └ firstpost.md
| └ secondpost.md
| └ thirdpost.md
| └ fourthpost.md
├ feed/
| └ feed.njk
| └ htaccess.njk
これらのファイルがコンパイルされることで、_site/
以下に HTML ファイルが生成されます。_site/
の中身に関してはリストでは省略しています。
_includes/
以下に保管したファイルは、コンパイル時に _site/
に HTML ファイルが出力されません。
特に設定がなければ、index.njk
は index.html
として、
特定の名前のついたファイル(ex.archive.njk
)はディレクトリ名をその名前とした index.html
ファイルとして(ex.archive/index.html
)出力されます。
出力される HTML のファイル名は、のちに述べる permalink の設定によって自由に変更することが出来ます。
プロジェクトルート直下の .eleventy.json
は 11ty の動作に関する設定ファイルで、11ty の動作や入出力ディレクトリなどをカスタマイズしたい場合は主にこのファイルを触っていくことになります。
また、eleventy-base-blog のリポジトリには元々存在しませんが、説明の便宜上 sample.njk
を生成しています。こちらは本記事の説明の都合上追加したファイルですので、都度内容の変化するサンプルコードとして読んでいただければ幸いです。
基本事項: YAML front-matterの参照
まず 11ty の基本的な使い方ですが、各ファイルに front-matter という記法で、変数やテンプレートファイルの読み込みを設定します。
front-matter は ---
で区切った YAML 形式で記述し、front-matter に記述した値は .njk
ファイルであれば、マスタッシュ記法 {{}}
にて参照することが可能です。
---
pageTitle: Hello 11ty
txt: Hi
---
<!doctype html>
<html>
<head>
<title>{{ pageTitle }}</title>
</head>
<body>
<p>{{ txt }}</p>
</body>
</html>
このファイルは以下のように出力されます。
<!doctype html>
<html>
<head>
<title>Hello 11ty</title>
</head>
<body>
<p>Hi</p>
</body>
</html>
eleventy-base-blog のトップページを眺める
まずはトップページである _site/index.html
を生成するファイルを確認します。
eleventy-base-blog のトップページは、以下キャプチャのようにブラウザで出力されます。
このトップページは以下のファイルから構成されています。
- base.njk
- home.njk
- index.njk
- postslist.njk
ページの中核を構成するのは index.njk
で、このファイルからテンプレートである base.njk
, home.njk
、インクルードファイルとして postslist.njk
を読み込む、という形になっています。
ブラウザ上の構成は以下キャプチャのようになります。
11ty によるテンプレート継承
layout
をキーとして_includes/
内のファイルを指定することで、テンプレート継承を行うことができます。
eleventy-base-blog の index.html においては _include/layouts/home.njk
をまずテンプレートとして指定しています。
---
layout: layouts/home.njk
eleventyNavigation:
key: Home
order: 1
---
<h1>Latest 3 Posts</h1>
{% set postslist = collections.posts | head(-3) %}
{% set postslistCounter = collections.posts | length %}
{% include "postslist.njk" %}
<p>More posts can be found in <a href="{{ '/posts/' | url }}">the archive</a>.</p>
index/html
のテンプレートとして指定されている home.njk
の中身は
---
layout: layouts/base.njk
templateClass: tmpl-home
---
{{ content | safe }}
となっており、更に base.njk
をレイアウトとして持ちます。
front-matter に記載されている templateClass: tmpl-home
は base.njk
に渡り、<main>
タグのクラス名条件分岐に使用されているようです。
<!-- mainタグ部分 -->
<main{% if templateClass %} class="{{ templateClass }}"{% endif %}>
<div class="warning">
<ol>
<li>Edit the <code>_data/metadata.json</code> with your blog’s information.</li>
<li>(Optional) Edit <code>.eleventy.js</code> with your <a href="https://www.11ty.dev/docs/config/">configuration preferences</a>.</li>
<li>Delete this message from <code>_includes/layouts/base.njk</code>.</li>
</ol>
<p>
<em>This is an <a href="https://www.11ty.io/">Eleventy project</a> created from the <a href="https://github.com/11ty/eleventy-base-blog">
<code>eleventy-base-blog</code> repo</a>.</em>
</p>
</div>
{{ content | safe }}
</main>
11ty では、このように入れ子構造でのテンプレート継承が可能です。
また base.njk
に渡されている templateClass: tmpl-home
のように、変数によってテンプレートの制御を行うこともできます。
しかし 11ty の front-matter によるテンプレート継承では、 block 構文はサポートされていません。
11ty の front-matter ではなく、Nunjucks のテンプレート継承記法である {% extends %}
でテンプレート継承を行うことで block 構文の使用が可能になりますが、こちらは front-matter との併用はできないようです。
Eleventy Documentation: NUNJUCKS
SUPPORTED FEATURES
{% extends 'base.njk' %} looks in _includes/base.njk. Does not process front matter in the include file.
JSON ファイルから変数を参照する
変数の管理は front-matter だけでなく、外部ファイルへの切り分けが可能です。
デフォルト設定ではプロジェクトルート直下の _data/
内に保存された .json
ファイルはグローバルデータとして各ファイルから参照することができます。
eleventy-base-blog では _data/metadata.json
がグローバルデータファイルとして保存されているので、base.njk
のヘッダー部分を参考に、参照方法を確認してみます。
<!--header部分-->
<header>
<h1 class="home">
<a href="{{ '/' | url }}">{{ metadata.title }}</a>
</h1>
{#- Read more about `eleventy-navigation` at https://www.11ty.dev/docs/plugins/navigation/ #}
<ul class="nav">
{%- for entry in collections.all | eleventyNavigation %}
<li class="nav-item{% if entry.url == page.url %} nav-item-active{% endif %}">
<a href="{{ entry.url | url }}">{{ entry.title }}</a>
</li>
{%- endfor %}
</ul>
</header>
h1
タグ内の {{ metadata.title }}
という記述にあるように、_data
内のデータファイル名を含めて JSON オブジェクトを指定することで、グローバルデータを参照することができます。
また、_data/
ディレクトリ外でも .11tydatafile.json
という拡張子を用いて
- テンプレートファイル内のみで使用できるデータ(テンプレートデータファイル)
- ディレクトリ内で共通使用できるデータ(ディレクトリデータファイル)
を設定することができます。
11ty では一つのデータについて複数箇所で記述されている場合、影響範囲の狭いものが優先されます。
従って、グローバルデータファイル、テンプレートデータファイル、ディレクトリデータファイルに同じ変数についての記述があった場合、
テンプレートデータファイル(優先度 高) > ディレクトリデータファイル(優先度 中) > グローバルデータファイル(優先度 低) の順で反映されます。
テンプレートデータファイルとして使用する場合
テンプレートファイル名と同様のファイル名.11tydatafile.json
として、テンプレートファイルと同じ場所に保存します。
eleventy-base-blog においての例としては archive.11tydatafile.json
というファイルをプロジェクトルート直下に保存することで archive.njk
内のみで使用したいデータを JSON ファイルとして切り分けることができます。
ディレクトリデータファイルとして使用する場合
ディレクトリ名と同様のファイル名.11tydatafile.json
として、使用したいディレクトリ直下に保存します。
eleventy-base-blog においての例としては posts.11tydatafile.json
というファイルを posts/
に保存することで、posts/
内のみで使用したいデータを JSON ファイルとして切り分けることができます。
なお 11ty において .md
ファイルはデフォルトでは liquid
テンプレートとして前処理されるようで、マスタッシュ記法 {{}}
で変数を参照することができます。
Eleventy Documentation: MARKDOWN
Markdown files are by default pre-processed as Liquid templates. You can change this default in your configuration file (or disable it altogether). To change this for a single template and not globally, read Changing a Template’s Rendering Engine.
パーマリンクを設定する
11ty のデフォルト設定では index.njk
は index.html
として、
特定の名前のついたファイル(ex.archive.njk
)は出力ディレクトリ名をその名前とした index.html
ファイルとして(ex.archive/index.html
)出力されます。
出力される URL やファイル名を制御したい場合、front-matter に permalink を指定します。
permalink: /posts/
上記の記述によって archive.njk
は _/site/post/index.html
として出力されます。
また、index.html
ではなく archive.html
としたい場合は、拡張子を含め以下のように記述することができます。
permalink: /posts/archive.html
11ty の提供するデータを扱う
11ty がデフォルトで提供するデータとして、各ページに関するデータがあります。具体的には以下のデータが page
オブジェクトとして保持されており、特別な設定無しで page
をキーに参照することができます。
- url : ページが出力されるURLが取得されます。
- fileSlug : 拡張子の除かれたソースファイル名が取得されます。1
- filePathStem : 拡張子の除かれたソースファイルのパスが取得されます。
- date : デフォルトではファイルの作成日が取得されます。2
- inputPath : ソースファイルのパスが取得されます。
- outputPath : 出力ファイルのディレクトリパスが取得されます。
日付を扱う
11ty では {{ page.date }}
でファイルの生成日や最終更新日を参照することができます。
例として posts/firstpost.md
を取りあげます
---
title: This is my first post.
description: This is a post on My Blog about agile frameworks.
date: 2018-05-01
tags:
- another-tag
layout: layouts/post.njk
---
上記の場合 {{ page.date }}
で参照したデータは firstpost.md
の front-matter で上書きされ Wed Jul 04 2018 09:00:00 GMT+0900 (日本標準時)
が返されます。
front-matter に date オブジェクトが無かった場合、11ty はデフォルトでファイルの作成日を返すようになっています。
また、日付ではなく date オブジェクトのプロパティとして Created
や Last Modified
を指定することによって、ファイルの生成日や最終更新日を取得することができます。
コレクションを使用する
11ty では作成した全てのページに関する情報を コレクション として保管します。
コレクションとして取得できるデータは以下のリストになります。
- inputPath : ソース入力ファイルへのフルパスが取得されます。
- fileSlug : 拡張子の除かれたソースファイル名が取得されます。1
- outputPath : 出力ファイルへのフルパスが取得されます。
- url : 各ページへのリンクに使用されるURLが取得されます。
- date : デフォルトではファイルの作成日が取得されます。2
- data : レイアウトから継承されたデータを含む、コンテンツのすべてのデータが取得されます。
- templateContent : レイアウトラッパーを含まない、テンプレートのレンダリングされたコンテンツが取得されます。
{{ collections.all }}
で上記データオブジェクトを全ページ分取得することができます。
また、各ファイルの front-matter に tags: xxx
を指定しておくことで、{{ collections.xxx }}
によって tags: xxx
を持つファイルに絞り込んだコレクションを取得できるようです。
sample.njk
に、全ページのスラッグとURLを対応させたリストを出力する、簡単なサンプルコードを書いてみます。
---
layout: layouts/home.njk
---
<ul>
{% for post in collections.all %}
<li>
{{ post.fileSlug }}: <a href="{{ post.url }}">{{ post.url }}</a>
</li>
{% endfor %}
</ul>
以下キャプチャのように、各ページへのリンク集が作成されたかと思います。
ページネーションを使用する
eleventy-base-blog では page-list.njk
にて、各ページへのリンク集が作成されています。こちらは pagenation を使用しているようです。
ここでは特に front-matter に指定されている pagination オブジェクトに着目していきます。
---
pagination:
data: collections.all
size: 20
alias: entries
layout: layouts/home.njk
permalink: /page-list/{% if pagination.pageNumber > 0 %}{{ pagination.pageNumber }}/{% endif %}
---
<table>
<thead>
<th>URL</th>
<th>Page Title</th>
</thead>
<tbody>
{%- for entry in entries %}
<tr>
<td><a href="{{ entry.url }}"><code>{{ entry.url }}</code></a></td>
<td>{{ entry.data.title }}</td>
</tr>
{%- endfor %}
</tbody>
</table>
上記の page-list.njk
では data: collections.all
の記述によって、データソースをコレクションから20ページ分取得します。
20ページ以上ある場合は
permalink: /page-list/{% if pagination.pageNumber > 0 %}{{ pagination.pageNumber }}/{% endif %}
の指定によって、次ページが自動生成されます。
また、alias: entries
の指定によって、colletions.all
を entries
として取得することができます。pagination の詳細な機能については公式ドキュメント PAGINATION のページをご参照ください。
入出力ディレクトリ等の変更について
入出力のディレクトリ、グローバルデータディレクトリ等のパスは、11ty の設定ファイル .eleventy.js
に設定を記述することで変更が可能です。
ディレクトリの設定はデフォルトでは以下のようになっています。
- 入力ディレクトリ(input): プロジェクトルート
- 出力ディレクトリ(output): _site
- インクルードディレクトリ(includes): _includes
- データディレクトリ(data): _data
以下のように dir オブジェクトを設定することで、これらの設定を上書きすることができます。
module.exports = {
dir: {
input: "views",
output: "dist",
includes: "my_includes",
data: "lore"
},
};
他にも使用するテンプレートエンジンの設定やウォッチターゲットの追加などの設定はこの .eleventy.js
を変更することで行います。詳しくは公式ドキュメントの CONFIGURATION をご参照ください。
感想
はじめに 11ty の使い方を確認していた時は「データが front-matter 一箇所にまとまって便利そうだなー」くらいに思っていたのですが、具体的な使用方法や設定方法、機能などを確認していくと、中〜大規模サイト構築に向けた機能があるだけでなく、環境構築の自由度が高く、柔軟性の高い静的サイトジェネレータであるという印象を持ちました。
自分の開発環境に合わせて、ディレクトリ構造のカスタマイズや SCSS のコンパイルなどと合わせた環境構築ができれば、静的サイト製作においてはかなり強力な静的サイトジェネレーターとして力を発揮してくれるのではないでしょうか。
次は現在の自身の開発環境に合わせて 11ty の環境構築を進めて行こうかと思っています。
-
ファイル名が
index.**
となっている場合は親ディレクトリ名が返されます。詳細は ELEVENTY SUPPLIED DATA : fileSlug をご参照ください。 ↩ ↩2 -
詳細は CONTENT DATES をご参照ください。 ↩ ↩2