Eleventy入門(第1回) - 11tyで手早く静的サイトを作成する

| 12 min read
Author: noboru-kudo noboru-kudoの画像

本サイトは開設当初から静的サイトジェネレーター(SSG)としてEleventyを使っています。
もう1年以上使っていますが、特に大きな問題なく運用できています。

そんなEleventyが2023-02-08にv2.0となりました[1]

Eleventyはコンテンツ重視の静的サイト作成に大きなアドバンテージを持っていますが、特に日本では今ひとつ認知度がないと感じます。
そこで、これまでの運用経験からEleventyの入門シリーズを書いてみようかと思います。

Eleventyの特徴

#

EleventyはNode.jsベースの静的サイトジェネレーターです。
主に以下の特徴があります。

  • デフォルトでゼロコンフィグ。簡単に導入できる。
  • 複数テンプレート言語をサポートし、各々は併用OK(HTML、マークダウン、Liquid、Nunjucks、etc...)。
  • クライアント(ブラウザ)で動作するJavaScriptなし。パフォーマンスやSEOに強い。

このような特性から、ブログやドキュメントサイトのようなコンテンツベースの静的サイトが得意です。
類似のツールとしては、Astroが近いのかなと思います[2]

好みのフレームワークでクライアント処理を追加する

デフォルトではクライアントで動作するJavaScriptはありませんので、そのままではUIにリアクティブ性を持たせたり、リアルタイムにデータフェッチするようなことはできません。
ただ、Eleventyではアイランドアーキテクチャに対応した公式プラグインが用意されています。
これを導入すれば、SSGのメリットであるパフォーマンスを損なうことなく、好きなフレームワークでクライアント処理を追加できます。
詳細は以下公式ドキュメントに各フレームワークの実装例を含めて記載されています。興味のある方はご参照ください。

本サイトでもこれを導入しており、静的サイトを基本としながらも、部分的にPreactでクライアント処理を追加しています。

コンテンツのビルド速度の点では、Go言語ベースのHugoには及びませんが、JavaScriptベースの静的サイトジェネレーターでは最高クラスとのことです。

JamstackトレンドでみるEleventyの成長

2022年のJamstack Serveyの結果から見ても、Eleventyは静的サイトジェネレーターで一定のシェア(19%)と満足度スコア(3.8)を獲得しています。

これを受けたNetlifyの予想記事では、2023年も静的サイトジェネレーターとしてEleventyは成長が継続すると予想しています。

Static site generators: a big leap forward for 11ty
Rating: A+
Our riskiest prediction paid off . At 19% share 11ty is still behind Gatsby’s 28%, but 11ty gained 2% in share while Gatsby lost 9%. We think 11ty’s momentum will continue given its stellar 3.8 satisfaction score.

引用元: Jamstack Trends: How will we develop in 2023?

Eleventyのセットアップ

#

任意のnpmプロジェクトにインストールします。

npm install --save-dev @11ty/eleventy

Eleventyは実行環境(クライアント側)としてのJavaScriptはありませんので、devDependenciesで構いません。
ここでは、現時点で最新のv2.0.0をインストールしました。

最もシンプルな静的サイトを作成する

#

ゼロコンフィグを謳っているだけあって、もうこの時点でサイトを作成できます。
ここでは、ローカル環境で最小限の静的サイトを動作させてみます。

プロジェクトルートに、以下の内容でindex.liquidというファイルを配置します。

<html lang="ja">
<head>
  <title>Eleventyサンプル</title>
</head>
<body>
  <h1>Eleventyサンプル</h1>
  <p>バージョン: {{ eleventy.version }}</p>
</body>
</html>

一見HTMLですが、{{ eleventy.version }}の部分は、Liquidというテンプレート言語の文法になっています。
特徴のところでも触れましたが、Eleventyは複数のテンプレート言語をサポートしています。Liquidはその中の1つで、Shopifyで開発されているものです。

ここでは組み込みの変数(eleventy.version)からEleventyのバージョンを出力しています[3]

Eleventyでサポートするテンプレート

Eleventyでは多数のテンプレートをサポートしているだけでなく、各テンプレートは併用可能です。
現時点での公式ドキュメントでは、以下のテンプレートをサポートしています。

  1. Liquid
  2. Nunjucks
  3. マークダウン
  4. HTML
  5. WebComponents(WebC)
  6. JavaScript
  7. Handlebars
  8. Mustache
  9. EJS
  10. HAML
  11. Pug

かなりの数でどれを使うか悩むところですね。公式ドキュメントだとほとんどがレイアウトとしてLiquidまたはNunjucks、コンテンツにマークダウンが使われていますので、こだわりがなければその辺りを採用するのが無難かなと思います。
とはいえ、v2.0.0以降で利用可能になったWebComponents(WebC)は個人的に注目しています。

なお、デフォルトでは拡張子で使用するテンプレートエンジンが決まりますが、設定で切り替え可能です。
詳細は公式ドキュメントを参照してください。

ここで、Eleventyの起動コマンドを実行します。
ローカル環境ではEleventyにビルトインされているDevサーバーを使います。

npx @11ty/eleventy --serve
[11ty] Writing _site/index.html from ./index.liquid
[11ty] Wrote 1 files in 0.11 seconds (v2.0.0)
[11ty] Watching…
[11ty] Server at http://localhost:8081/

ここでビルドが実行されて、先程のテンプレートがLiquidテンプレートエンジンで変換されています。
ビルド結果は、デフォルトの_siteディレクトリに出力されています。
実際の_site/index.htmlの内容は以下です。

<html lang="ja">
<head>
  <title>Eleventyサンプル</title>
</head>
<body>
  <h1>Eleventyサンプル</h1>
  <p>バージョン: 2.0.0</p>
</body>
</html>

セットアップしたEleventyのバージョン2.0.0が出力されていることが分かります。

また、--serveオプションによりビルド後にEleventyビルトインのDevサーバーが起動し、このコンテンツを配信している状態になります。
ブラウザでhttp://localhost:8080/ にアクセスすれば上記ページが表示されます。

なお、この状態でテンプレートファイルを更新すればリアルタイムにビルドが実行され、サイトも更新されます(ホットリロード)。

インクリメンタルにビルドする

コンテンツが増えてくると、ホットリロード時のビルド時間がかかるようになります。
そのような状態になった場合は、--incrementalオプションをつけると増分ビルドになり、この時間は劇的に高速化されます。

npx @11ty/eleventy --serve --incremental

v2.0.0からは--ignore-initialを組み合わせると、初回ビルドすらスキップして、前回ビルド結果を再利用できます。
ただし、Devサーバーを起動中の変更のみを増分ビルド対象として認識するため注意が必要です(つまり、起動していない間の変更はフルビルドしないと反映されません)。
詳細は公式ドキュメントを参照してください。

なお、サーバー環境やホスティングサービスにデプロイする際は、--serveなしで同コマンドを実行します。
後は_siteディレクトリ配下を対象環境にデプロイするだけです。
もちろん、これはGitHub Actions等のCI/CDパイプライン上での実行になるかと思います。

マークダウンでコンテンツを作成する

#

先程はシンプルなLiquidベースのHTMLをコンテンツに使いましたが、ブログやドキュメントサイト等では、一般的にマークダウンで作成することが多いかと思います。
ここではマークダウンを使ってコンテンツを作成してみます。

その前にコンテンツページ共通のレイアウトを定義します。_includesディレクトリを作成し、その中に以下のファイル(base.liquid)を配置します。

<html lang="ja">
<head>
    <title>Eleventyサンプル</title>
</head>
<body>
<header>
    <h1>Eleventyサンプル</h1>
</header>
<article>
{{ content }}
</article>
<footer>
    <p>&copy; mamezou-tech</p>
</footer>
</body>
</html>

先程と同様に、Liquidテンプレートで記述したものです。

Eleventyでは、このディレクトリ内のファイルは他のテンプレートから利用される特殊なものとして扱われます[4]
つまり、このディレクトリ配下はビルドしても単独のページ(HTML)として出力されません。

このレイアウトファイルのポイントは、{{ content }}の部分です。
Eleventyでは、このcontent変数に子テンプレートの内容(変換結果)が設定されます。
ここでは、この内容をそのままHTMLに挿入するようにしています。

後はこれを利用する実際のコンテンツ(子テンプレート)です。プロジェクトルートに以下のマークダウン(sample.md)を作成します。

---
layout: base
---
# サンプルページ
Eleventyのドキュメントはこちらです!!

- [Eleventy Doc](https://www.11ty.dev/)

上部のメタ情報(Front Matterといいます)にlayout: baseと親テンプレートを指定しています[5]
こうするとEleventyは、このテンプレートをbaseレイアウト(先程作成したbase.liquid)の子テンプレートとして認識します。

以降は通常のマークダウン記法で記述するだけです。

この段階でDevサーバーが起動していれば、Eleventyがマークダウンファイルの追加を検知して_site/sample/index.htmlにHTMLが出力されているはずです。

<html lang="ja">
<head>
    <title>Eleventyサンプル</title>
</head>
<body>
<header>
    <h1>Eleventyサンプル</h1>
</header>
<article>
<h1>サンプルページ</h1>
<p>Eleventyのドキュメントはこちらです!!</p>
<ul>
<li><a href="https://www.11ty.dev/">Eleventy Doc</a></li>
</ul>

</article>
<footer>
    <p>&copy; mamezou-tech</p>
</footer>
</body>
</html>

LiquidテンプレートにマークダウンのコンテンツがHTMLに変換されて挿入されているのが分かります。
ブラウザからhttp://localhost:8080/sample/にアクセスすれば、Webページとして参照できます。

Eleventyでは、このマークダウンのHTML変換にmarkdown-itライブラリを使っています。
通常はmarkdown-itそのままでなく、カスタマイズやプラグインで拡張したい場合が多いかと思います。
後述の設定ファイルを使えば、以下のように公開されているmarkdown-itプラグインや自作プラグインも適用できます。

Eleventyの設定ファイルを理解する

#

これまでは全てデフォルトの状態で使ってきましたが、Eleventyを使いこなすには、設定ファイルを理解する必要があります。
Eleventyのカスタマイズや拡張はこの設定ファイルが必ず登場します。

Eleventyの設定ファイルは、プロジェクトルートに配置します。
デフォルトでは、以下のいずれかのファイル名で作成します。

  • .eleventy.js
  • eleventy.config.js
  • eleventy.config.cjs

このうち、eleventy.config.js/eleventy.config.cjsはv2.0.0以降から登場しています[6]

Eleventyの設定ファイルは、以下のように記述します。

module.exports = function(eleventyConfig) {
  
  // 引数のeleventyConfigに設定をする
  
  // 戻り値でデフォルト挙動をカスタマイズ
  return {
    // ...
  };
};

Eleventyの設定(eleventyConfig)を引数で受け取り、基本はそれに対してカスタマイズを加えていきます。
また、ディレクトリ構造やテンプレートエンジン等、戻り値として設定するものもあります。

以下は利用頻度が高い(と思う)設定です。

Eleventyをカスタマイズする

#

ここで、Eleventyの設定ファイルを追加して、少し実践的なものに変えていきます。

以下のEleventy設定ファイル(ここではeleventy.config.jsとしています)を配置します。

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

module.exports = function(eleventyConfig) {
  // ①
  eleventyConfig.addPlugin(syntaxHighlight);
  // ②
  eleventyConfig.addPassthroughCopy("./src/css");

  return {
    dir: {
      // ③
      input: "src",
      // ④
      output: "public"
    }
  };
};

ここでは、以下の設定をしています。

  • ① Eleventyプラグインでコードスニペットのシンタックスハイライト有効化
  • ② スタイルシート(CSS)はそのままコピー
  • ③ ベースディレクトリをsrc配下に変更(デフォルトはプロジェクトルート)
  • ④ ビルド結果の出力先をpublicに変更(デフォルトは_site)

なお、Eleventyのプラグインは事前にnpmインストールしておきます。

npm install --save-dev @11ty/eleventy-plugin-syntaxhighlight

プラグインの詳細は、以下公式ドキュメントを参照してください。

この設定では、プロジェクトのディレクトリ構成は以下になります。

.
├── src // ベースディレクトリ
│   ├── _includes
│   │   └── base.liquid
│   ├── css // スタイルシート
│   │   └── style.css
│   └── post
│       └── sample.md
├── public // ビルド結果出力先
│   ├── css
│   │   └── style.css // パススルーコピー
│   └── sample
│       └── index.html // URL設定変更(後述)
├── eleventy.config.js // Eleventy設定ファイル
├── package-lock.json
└── package.json

勘が鋭い方は分かったかもしれません。Astroのプロジェクト構造を模倣してみました。

先程作成したサイトをベースにすると、src配下のファイルは以下のようなものになります。

src/css/style.css

#
:root {
  --base-color: #b780ea;
}

header {
  background-color: var(--base-color);
  padding: 5px;
}

header > h1 {
  font-size: 1.2rem;
}

footer {
  background-color: var(--base-color);
  padding: 2px;
}

サンプルのCSSです。これはテンプレート処理されずそのまま出力ディレクトリにコピーされます。

レイアウトファイル(src/_includes/base.liquid)

#
<html lang="ja">
<head>
    <title>Eleventyサンプル</title>
    <link href="/css/style.css" rel="stylesheet" />
    <link href="https://unpkg.com/prismjs@1.20.0/themes/prism-okaidia.css" rel="stylesheet">
</head>
<body>
<header>
    <h1>Eleventyサンプル</h1>
</header>
<article>
{{ content }}
</article>
<footer>
    <p>&copy; mamezou-tech</p>
</footer>
</body>
</html>

以前作成したレイアウトファイルに2つのCSSリンクを追加しています。

最初のCSSはsrc/cssに配置したもので、それがパススルーコピーされたものを参照しています。

2つ目はEleventyのシンタックスハイライトプラグインの利用で必要なCSSです。
実態はPrism themesから提供されているものです。

src/post/sample.md

#
---
layout: base
permalink: /sample/
---
# サンプルページ
Eleventyの設定ファイルは以下のようになります。
```javascript
const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");

module.exports = function(eleventyConfig) {
  eleventyConfig.addPlugin(syntaxHighlight);
  eleventyConfig.addPassthroughCopy("./src/css");

  return {
    dir: {
      input: "src",
      output: "public"
    }
  };
};
```

シンタックスハイライトを有効にしていますので、コードスニペットを記述してみました。
また、メタ情報(Front Matter)にpermalinkを追加し、ページURLに/sample/を指定しました。
これを指定しない場合のデフォルトは、ベースディレクトリ(src)からのパス(/post/sample/)がURLとなります。

ディレクトリレベルで共通のデータをまとめる

ここではマークダウンのメタ情報としてレイアウトやページURLを指定していますが、個別ファイルではなくディレクトリレベルで指定したいところです。
これは、ディレクトリ名と同名のJSON(またはJavaScript)を該当ディレクトリに配置することで実現できます。

この例では、src/postディレクトリ内に以下のpost.jsonを作成しす。

{
  "layout": "base",
  "permalink": "/{{ page.fileSlug }}/"
}

こうすることで、マークダウンに記述したメタ情報を削除しても、同じ効果が得られます。
なお、マークダウンのメタ情報が存在する場合は、ディレクトリレベルのデータとマージされます。両者に同名のキーが含まれる場合はマークダウンの方が優先されます。

ここで使っているpage.fileSlugはEleventyが提供する変数でURL用のファイル名が設定されます。詳細は以下公式ドキュメントを参照してください。

出力結果

#

この例では以下のようなページが表示されました。

screen

スタータープロジェクトで実践的なサイトを手早く構築する

Eleventyはカスタマイズの自由度が高く、設定ファイルを作成するにしてもどこから手を付けてよいか分からないかもしれません。
また、(筆者のように)デザインが不得手な方は、出来合いのものをカスタマイズして使いたいことも多いかと思います。

このような人のために、Eleventyではコミュニティ駆動のスタータープロエジェクトが公開されています。
まずはこの中から好みのものを見つけて、自分のサイト向けにカスタマイズしていく形にすると、見た目も良く、各種設定が最適化されたサイトを簡単に構築できます。

Lighthouseのスコアも掲載されていますので、選択の参考にすると良いかと思います。

まとめ

#

今回は、Eleventyを使い始める手順についてご紹介しました。
使用するテンプレート言語の知識はある程度必要ですが、簡単にサイトを作成できることが分かります。
また、デフォルトでは、クライアントサイドのJavaScriptはありませんので、SEOやパフォーマンス観点でも強力です。

本サイトでも、既に総ページ数は600ページを超えてきましたが、Eleventyで快適(?)な執筆活動ができています。

次回以降、Eleventyのプラグインやショートコード・フィルター等について書きたいと思います。


関連記事


  1. 本サイトは2.0のCanaryバージョンから使っていたため、大きな変更なくv2.0にバージョンアップできました。 ↩︎

  2. Astroは本サイトのブログ記事でも紹介していますのでご参考ください。個人的にはAstroはTypeScriptをファーストクラスサポートしているのが魅力です。 ↩︎

  3. Eleventy組み込み変数の詳細は公式ドキュメントを参照してください。 ↩︎

  4. _includesというディレクトリ名は設定により変更可能です。詳細は公式ドキュメントを参照してください。 ↩︎

  5. ここではYAMLで記述していますが、JavaScriptやJSON形式もサポートしています。 ↩︎

  6. これ以外を設定ファイルとして使用する場合は、CLIオプション(--config)で指定します。 ↩︎

豆蔵では共に高め合う仲間を募集しています!

recruit

具体的な採用情報はこちらからご覧いただけます。