本文へジャンプ

シンプルな静的サイトジェネレーター、Eleventyを試す

Posted by MMR

突然ですが、「ミニマム」とか「シンプル」が好きです。自然と心惹かれます。
ミニマムな暮らし、素材を生かしたシンプルな味付け、ミニマムでシンプルな実装...

ということで、ミニマムでシンプルな静的サイトジェネレーター、Eleventy を試してみたいと思います。

インストール

プロジェクトのディレクトリに package.json を作成し、Eleventyをインストールします。

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

インストール後、 package.json ファイルの記述を少し整頓してこのようになりました。
npm run build で実行、npm run serve で開発用サーバーを立ち上げファイルの変更を監視する scripts を追加しています。

package.json

    {
        "name": "11ty-demo",
        "version": "1.0.0",
        "private": true,
        "scripts": {
            "build": "eleventy",
            "serve": "eleventy --serve"
        },
        "devDependencies": {
            "@11ty/eleventy": "^0.11.1"
        }
    }

テンプレートからHTMLを生成

Eleventyは多くのテンプレート言語に対応しています。1今回はページ毎に .md ファイル、ページのテンプレートとして .njk ファイルを作成していきましょう。

index.md ファイルでは継承するテンプレートをfront-matterで設定します。(「---」で囲まれた部分)

index.md

    ---
    layout: template.njk
    ---

    # 見出し
    本文

.njk ファイルは _includes/ 以下に配置します。

_includes/template.njk

    <!doctype html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>タイトル</title>
    </head>

    <body>
    {{ content | safe }}
    </body>
    </html>

作成したところで、さっそくHTMLを生成してみます。

    $ npm run build

    > 11ty-demo@1.0.0 build
    > eleventy

    Writing _site/index.html from ./index.md.
    Wrote 1 file in 0.11 seconds (v0.11.1)

_site/ 以下に index.html が生成されました。 template.njk が継承され、 index.md の内容が出力されたのが確認できます。

_site/index.html

    <!doctype html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>タイトル</title>
    </head>

    <body>
    <h1>見出し</h1>
    <p>本文</p>

    </body>
    </html>

ディレクトリの設定を変更

Eleventy のデフォルトの動作によりソースファイルはディレクトリ直下、出力ファイルは _site/ 以下にある状態ですが、設定ファイルを用意するとディレクトリを変更することができます。

今回はソースファイルを置くディレクトリを src/ 以下に、出力ファイルを dist/ 以下に指定したいと思います。

.eleventy.js

    module.exports = {
        dir: {
            input: "src",
            output: "dist"
        }
    };

これでソースファイルは src/ 以下、出力ファイルは dist/ 以下になりました。今回はそのままにしますが、src/_includes/ の名前も変更することができます。

.eleventy.js

    module.exports = {
        dir: {
            ...,
            // _includes の名前を変更
            includes: "_inc",
            // 相対パスでも指定可能
            includes: "../_inc",
            ...
        }
    };

配列を利用した複数ページの作成

Eleventy はかなり柔軟にデータを扱うことができ、配列を利用することで1つのテンプレートを元に複数のHTMLを生成することができます。ここで少し遊んでみたいと思います。

Yu-Gi-Oh! API を利用してカードの枚数毎にHTMLを生成し、カードデッキを作ります。

外部APIからデータを取得

データを取得するために、node-fetch を使用します。事前にインストールしておきましょう。

    $ npm install node-fetch

次に src/cards/ ディレクトリを作成し、以下にデータ取得用に cards.11tydata.js ファイル、データを表示させる cards.njk ファイルを作成します。
[テンプレート名].11tydata.js といったようにテンプレートファイルと同じ名前でファイルを用意すると、そのテンプレート内だけで使用できるデータになります。

非同期でデータを取得し、カード40枚分2のデータを返すようにします。

src/cards/cards.11tydata.js

    const fetch = require('node-fetch');

    module.exports = function() {
    return fetch('https://db.ygoprodeck.com/api/v7/cardinfo.php?num=40&offset=40')
        .then(responce => responce.json());
    }

ページのテンプレートを作成

次にテンプレートファイルです。カードの名前・タイプ・画像を表示し、次のカードがドローできるようにリンクを設置します。

src/cards/cards.njk

    ---
    layout: template.njk
    pagination:
        data: data
        size: 1
        alias: card
    ---

    <h1 class="Heading">
        <span class="Heading__main">{{ card.name }}</span>
        <span class="Heading__sub">{{ card.type }}</span>
    </h1>
    <div class="Card"><img src="{{ card.card_images[0].image_url }}" alt=""></div>

    \{% if pagination.href.next %\}
    <p class="Draw"><a href="{{ pagination.href.next }}">Draw</a></p>
    \{% else %\}
    <p class="Draw">No next card! You lose...</p>
    \{% endif %\}

front-matter に追加した pagination は、Eleventy によって提供されるデータです。それを利用し、次に引くカードがなくなった場合は負け2になるので、次のページがない場合には「No next card! You lose...」と出力されるようにしました。

俺のターン!ドロー!

ここで出力結果を見てみましょう。

dist/cards/index.html

    <!doctype html>
    <html lang="ja">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>遊戯王カードデッキ</title>
    </head>

    <body>
    <h1 class="Heading">
    <span class="Heading__main">Abominable Chamber of the Unchained</span>
    <span class="Heading__sub">Trap Card</span>
    </h1>
    <div class="Card"><img src="https://storage.googleapis.com/ygoprodeck.com/pics/80801743.jpg" alt=""></div>

    <p class="Draw"><a href="/cards/1/">Draw</a></p>
    </body>
    </html>

無事にドローできました。カードの名前・タイプ・画像が表示され、次のカードを引くためのリンクも設置されています。

    dist/
    ├ cards/
    │  ├ 1/index.html
    │  ├ .../index.html
    │  ├ 39/index.html
    │  └ index.html
    └ index.html

今回は40枚のカード分のデータがあるので、1ページ目は cards/ 直下の index.html、以降は1から連番のフォルダに出力されます。
front-matter に permalink の設定を追加することでフォルダ名の変更も可能です。

src/cards/cards.njk

    ---
    layout: template.njk
    pagination:
        data: data
        size: 1
        alias: card
    permalink: "cards/{{ card.id }}/" <- フォルダ名に配列のデータを利用することもできる。
    ---

さいごに

実は以前社内勉強会で少し触っていたのですが、ブログを書くにあたり改めてしっかり試してみました。

設定がとてもシンプルで機能としても十二分だと思います。特にテンプレート形式の柔軟さが便利ですね。
ちなみにCSSやJSを出力する機能はないので、その潔さもまた好きですが、使用する場合はEleventy外で考えていく必要があります。

ここまで書いておいてですが遊戯王のルールはほぼ知らない3ため、細かな粗相はご容赦ください。

  1. https://www.11ty.dev/docs/languages/
  2. マスタールール(2020年4月1日改訂版)対応公式ルールブック(PDF)
  3. 小学生くらいの頃に兄の対戦相手としておそらく弱いデッキを渡され、ルールが分からないまま何度も負かされ続けた思い出はあります。
Recent Entries
MD EVENT REPORT
What's Hot?
こんな僕たちの仲間に入りませんか?
Movable Type AWS 移管&アップグレード サービス
乃木坂・六本木 撮影配信スタジオ
すべてのコンテンツ/プラットフォームを、ひとつのコンテンツ管理システムで。