books.ginpei.dev GitHub

Eleventy

静的サイトジェネレーター。

初期設定

インストール

$ npm install -D @11ty/eleventy

ビルド

何か markdown ファイルを用意しておく。場所は差し当たりどこでも良い。パスとファイル名から URL が用意される。

ビルド。

$ npx @11ty/eleventy

_site/ 以下に出力される。

サーバー

--serve を与えるとウェブサーバーが起動する。ファイル変更を監視し自動で再出力、ブラウザーで開いていれば再読み込みまでしてくれる。便利。

ポートは 8080 。あるいは --port 3000 のように指定。

スクリプト

package.json:

{
"scripts": {
"build": "eleventy",
"start": "eleventy --serve"

テンプレートとレイアウト

_includes/ 以下に *.njk を設置。layout: で指定。

なお njk は Nunjucks (ヌンチャク)。

実装

_includes/basicLayout.njk:

---
title: (Not titled)
---

<!DOCTYPE html>
<html lang="en">
<head>
<title>{{ title }}</title>
</head>
<body>
<main>
{{ content | safe }}
</main>
</body>
</html>

利用

---
layout: basicLayout.njk
title: Hello World!

---


# Hello World!

変数とエスケープ

{{xxx}} で Nunjucks の変数の埋め込みになる。{{title}} とか。

文章やコード例として画面に {{ を表示したい場合は {% raw %}{% endraw %} で括る。

カスタマイズ

.eleventy.js を設置してカスタマイズできる。

例:

const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
const markdownIt = require("markdown-it");

module.exports = function (eleventyConfig) {
eleventyConfig.setLibrary(
"md",
markdownIt({
html: true,
linkify: true,
})
);

eleventyConfig.addPlugin(syntaxHighlight);
};

URL を自動リンク

markdown-it の linkify 機能を有効化する。

文章中に出現する https://example.com のような文字列を URL としてリンクさせる。スキームなしの example.com には反応しない。

const markdownIt = require("markdown-it");

// …

eleventyConfig.setLibrary(
"md",
markdownIt({
html: true,
linkify: true,
})
);

見出しにリンク

markdown-it のプラグイン markdown-it-anchor を使う。

const markdownItAnchor = require("markdown-it-anchor");
const md = markdownIt({});



md.use(markdownItAnchor, {
permalink: markdownItAnchor.permalink.headerLink({
safariReaderFix: true,
}),
});

permalink の設定でリンクの方法を指定できる。("🔗" を表示する等。) ドキュメント参照

ソースコードのシンタックスハイライト

公式プラグインを利用。中身は Prism.js らしい。

const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");

// …

eleventyConfig.addPlugin(syntaxHighlight);

加えてハイライト用の CSS をレイアウトで読み込む。

<link rel="stylesheet" href="https://unpkg.com/prismjs@1.28.0/themes/prism-okaidia.css">

テーマ一覧。

更新日を表示

更新日を自動で得る方法はないので、各記事 *.mddate を設定してテンプレートで表示する。書式は YAML が対応する YYYY-MM-DD 等にする。(例えば月を 1 桁で書くと駄目。)

---
title: なんかすごいおもしろい記事
date: 2021-05-21

---
{% if date %}
<time>{{ date }}</time>
{% endif %}

書式を守ると JavaScript の Date オブジェクトになる。.eleventy.js に整形フィルターを追加する。

module.exports = function (eleventyConfig) {
eleventyConfig.addFilter("toDate", (v) => articleDateToString(v));
/**
* @param {unknown} date
*/

function articleDateToString(date) {
if (!(date instanceof Date)) {
throw new Error(
"[articleDateToString] Date object expected but received " +
`${typeof date}: ${JSON.stringify(date)}`
);
}

return [
date.getFullYear(),
toTwoDigits(date.getMonth() + 1),
toTwoDigits(date.getDate()),
].join("-");
}

/**
* @param {number} number
*/

function toTwoDigits(number) {
return number.toString().padStart(2, "0");
}
{% if date %}
<time class="baseLayout-time">
{{ date | toDate }}
</time>
{% endif %}

記事のファイルパスから目次ページへのリンク作成

プロジェクトのルートに books/ ディレクトリーを用意して、その下に ja/ とか en/ とか置く感じの想定。

module.exports = function (eleventyConfig) {
eleventyConfig.addFilter("toHomePath", (v) => toHomePath(v));
/**
* @param {string} path
* @example
* // <a href="{{ page.inputPath | toHomePath }}">Home</a>
*/

function toHomePath(path) {
if (typeof path !== "string") {
throw new Error(
"[getPathLang] String expected but received " +
`${typeof path}: ${JSON.stringify(path)}`
);
}

const [cur, books, lang] = path.split("/");
if (cur !== "." || books !== "books" || lang.length !== 2) {
return "/";
}

return `/${lang}/`;
}
<a href="{{ page.inputPath | toHomePath }}">Home</a>