注目イベント!
アドベントカレンダー2024開催中!
一年を締めくくる特別なイベント、アドベントカレンダーを今年も開催しています!
初心者からベテランまで楽しめる内容で、毎日新しい技術トピックをお届けします。
詳細はこちらから!
event banner

Lume入門(第1回) - Denoベースの静的サイトジェネレーターLumeで静的サイトを手早く作る

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

当サイトもそろそろ開設から2年になろうとしています。
これを機(?)に、ページ生成に使っていた静的サイトジェネレーター(SSG)をLumeに変更しました。

以前はサイトの生成にEleventy(11ty)を使っていました。
Eleventyでも大きな不満はないのですが[1]、Denoが基盤のLumeに心惹かれて移行を決断しました。

移行にあたっては、サイト自体に加えて執筆体験に大きな変更が発生しないよう配慮しました。
その点でLumeはEleventyを参考に開発されており、Eleventyと機能レベルの互換性が高くとても移行し易かったです。

一通りLumeの機能を使ってみましたので、Lumeに関する入門記事やTipsを記事にしていきたいと思います。
初回はLumeのセットアップと基本的な使い方から見ていきます。

Information

2023-12-08にLumeがv2にメジャーアップデートしました。これに伴い本記事もv2で動作するよう更新しました。

Lumeセットアップ

#

前述の通りLumeはNode.jsではなくDenoで動作します。
未インストールの場合は、まずはDenoをインストールしましょう。
インストール方法は環境によって異なりますので、以下Denoの公式ページを参考にしてください[2]

次にLumeをセットアップします。Lumeの公式ドキュメントの通りに任意ディレクトリを作成して以下を実行します。

deno run -Ar https://deno.land/x/lume/init.ts
 ? Choose the configuration file format › _config.ts (TypeScript)
 ? Do you want to install some plugins now? › Maybe later

Lume configuration file saved: _config.ts

🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥

 Lume configured successfully!

    BENVIDO - WELCOME! 🎉🎉

🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥

Quick start:
  Create the index.md file and write some content
  Run deno task serve to start a local server

See https://lume.land for online documentation
See https://discord.gg/YbTmpACHWB to propose new ideas and get help at Discord
See https://github.com/lumeland/lume to view the source code and report issues
See https://opencollective.com/lume to support Lume development

Deno configuration file saved: deno.json

実行すると構成に関していくつか質問されます。
ここでは_config.tsの利用言語はTypeScript、プラグインは指定なし(Maybe later)としました。

直下に以下のファイルが作成されます。

.
├── _config.ts
└── deno.json

何だかnode_modulesがないのは気持ちがいいものですね。
deno.jsonはDeno自体の構成ファイルでNode.jsでいうpackage.jsonです。
_config.tsがLumeの設定ファイルです。初期状態は以下のようになっています。

import lume from "lume/mod.ts";

const site = lume();

export default site;

先ほどのセットアップ時の質問で任意のプラグインを指定していれば、ここにプラグインのセットアップコードが生成されます。
それ以外にもビルドのカスタマイズ、テンプレートのフィルター等、Lumeに関する設定全般をここで指定することになります。

マークダウンファイルから静的ページを生成する

#

まだ何の設定も追加していませんが、実はこの状態でマークダウンファイルを作成するだけでも、静的サイトジェネレーターとして機能します。

試しに以下のマークダウンファイル(index.md)を作成します。

---
title: Lumeで始めるブログサイト運営
url: /blogs/lume/
---

## Lumeとは

[Lume](https://lume.land/)はDenoで動作する静的サイトジェネレーター(SSG)です。

[公式ドキュメント](https://lume.land/docs/overview/about-lume/)によると、以下のような特徴を持っています。

- マークダウンやJavaScript、JSX、Nunjucksなど、複数フォーマットに対応
- 各プロセッサーのフックして柔軟に拡張可能
- Denoベースのランタイム環境

## インストール

まずは[Deno](https://deno.com/)をインストールしましょう!!

```shell
curl -fsSL https://deno.land/x/install/install.sh | sh
```

続いてLumeのセットアップです。

```shell
deno run -Ar https://deno.land/x/lume/init.ts
```

最初(---で囲われた部分)にフロントマターと呼ばれるタイトルやURL等のページのメタデータを設定しています。
このフロントマターの内容は任意ですが、一部のデータはLumeで特別なものとして扱われます。
例えば、ここで使われているurlは該当ページの公開URLとしてページ生成時のパスやファイル名として利用されます。
フロントマターの詳細は、以下公式ドキュメントを参照してください。

次に、ローカル確認用に開発モードでサーバーを起動します。

deno task serve
# 以下でも同じ
# deno task lume --serve

デフォルト3000番ポートでローカル環境にDEVサーバーが起動します。
ブラウザを起動してhttp://localhost:3000/blogs/lume/ にアクセスすると以下のようなページが表示されます。

dev server

味気ないページですがマークダウンファイルを作成しただけで、それが静的ページとしてHTMLに変換されブラウザで表示されることが確認できます。

この状態でマークダウンファイルを更新すると、Lumeは変更を検知して再ビルド後にブラウザをリロードしてくれます。ここでページの見栄えを確認しながら、ページを作り上げていく形になります。

ディレクトリレベルでフロントマターを共有する

フロントマターは各ページだけでなく、ディレクトリレベルで同じものもかなり多いかと思います。
Lumeではディレクトリに_data.*を配置することで、共通のフロントマターを指定できます。
詳細は以下公式ドキュメントを参照してください。

なお、同一キーを指定した場合は、ページレベルのフロントマターが優先されます。

ローカルポートを変更する

ローカルDEVサーバーの起動ポートを変更する場合は引数(--port)、または_config.tsで指定します。
以下はポートを8000番に変更する例です。

deno task serve --port 8000
# 以下でも同じ
# deno task lume --serve --port 8000
const site = lume({
  server: {
    port: 8000
  }
});

サーバーを起動せずに静的ページを生成する場合は、以下のコマンドを実行します。

deno task build
# 以下でも同じ
# deno task lume

デフォルトでは_siteディレクトリ配下にページが生成されています。
実際にデプロイする際には、このディレクトリ配下をそのままアップロードするだけです。

このようにゼロコンフィグの状態でも、簡単に静的サイトがプレビューやデプロイできることが実感できます。

出力先ディレクトリを変更する

出力先ディレクトリの変更もコマンド引数(--dest)または_config.tsファイルで行います。
以下はpublicディレクトリに変更する例です。

deno task build --dest public
# 以下でも同じ
# deno task lume --dest public
const site = lume({
  dest: "public"
});

スタイルシートでページの見栄えを良くする

#

ここで、設定をいくつか加えてもう少し見栄えの良いページにしていきます。
まずはページにスタイルを当てていきましょう。普通にCSSを作成してもいいのですが、せっかくなのでSCSSで作成してみます。

プロジェクトルート直下にcssをディレクトリを作成して、以下のSCSS(style.scss)を配置します。

@import url('https://fonts.googleapis.com/css2?family=Pacifico&family=Roboto:wght@400;700&display=swap');

$font-stack-body: 'Roboto', sans-serif;
$font-stack-heading: 'Pacifico', cursive;
$primary-color: #e74c3c;
$secondary-color: #f39c12;
$tertiary-color: #3498db;
$text-color: #2c3e50;
$background-color: #ecf0f1;

@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
  -moz-border-radius: $radius;
  -ms-border-radius: $radius;
  border-radius: $radius;
}

body {
  font-family: $font-stack-body;
  background-color: $background-color;
  color: $text-color;
  margin: 0;
  padding: 0;
}

header {
  background: linear-gradient(to right, $primary-color, $secondary-color);
  color: white;
  padding: 20px;

  h1 {
    font-family: $font-stack-heading;
    font-size: 2em;
  }
}

article {
  margin: 20px;
  padding: 20px;
  background-color: white;
  @include border-radius(10px);

  h2 {
    color: $tertiary-color;
    font-family: $font-stack-heading;
  }
}

footer {
  background: linear-gradient(to left, $secondary-color, $primary-color);
  color: white;
  text-align: center;
  padding: 10px;
  bottom: 0;
  width: 100%;
}

次に、これをマークダウンファイルから生成するHTMLに読み込ませます。これにはレイアウトファイルを使います。
レイアウトファイルはページの枠組みを定義するもので、各ページで共通の部分として作成します。

レイアウトファイルには多くのテンプレート言語がサポートされていますが、ここではMozillaのNunjucksを使います。

v2アップデートで組み込みテンプレートエンジンの変更

Lume v1まではNunjucksはビルトインのテンプレートエンジンでしたが、v2からはこれに代わりVentoがビルトインで組み込まれるようになりました。

Nunjucksを使う場合は、_config.tsに以下を追加します。

import nunjucks from "lume/plugins/nunjucks.ts";

const site = lume();
site.use(nunjucks()); // Nunjucksプラグインを使用

これでNunjucksでレイアウトが作成可能となります。

_includes/layoutsディレクトリを作成し、以下のblog.njkを配置します。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>{{ title }}</title>
  <link rel="stylesheet" href="/css/style.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css" />
</head>
<body>
<header>
  <h1>サンプルブログサイト</h1>
</header>

<main>
  <article>
    <h2>{{ title }}</h2>
    {{ content | safe }}
  </article>
</main>

<footer>
  <p>&copy; 2023 豆香ブログ</p>
</footer>
</body>
</html>

headタグ内で<link rel="stylesheet" href="/css/style.css" />としてCSSファイルを読み込んでいます。
ただし、先ほどSCSSとして配置していますのでこのままでは読み込みエラーとなります。これには後述のプラグインを使います。
また、それ以外にもコードハイライト用にPrismのCSS(prism.min.css)もCDNから追加しています。

その他にもいくつかポイントがあります。
まずは、変数としてtitleを使っていますが、これは先ほどマークダウンファイル作成時にフロントマターで指定したものです。テンプレートファイルではそのままプレースホルダーとして利用できます。

もう1つはcontentです。これは特殊な変数です。ここにはLumeによりレイアウトを使用しているテンプレート(この場合はマークダウンファイル)の本文が設定されます。
なお、Nunjucksのフィルターとして使われているsafeはNunjucksビルトインのフィルター[3]で、この内容(content)が安全なものとしてマークしています。

_includeディレクトリはページ生成対象外

レイアウトファイルを配置した_includeディレクトリは特殊なディレクトリとして認識され、ページ生成の対象とはなりません。
ここにはページ内で使われる部品も配置することから、レイアウトファイルは_include直下ではなくlayouts等のサブディレクトリに配置することが多いようです。

なお、このディレクトリ名も_config.tsで変更可能です。
以下は_commonに変更する例です。

const site = lume({
  includes: "_common"
});

// または
// site.includes([".njk"], "_common");

このレイアウトファイルを使用するようにマークダウンファイルを変更します。
これはマークダウンファイルのフロントマターでlayout変数を指定するだけです。

---
title: Lumeで始めるブログサイト運営
url: /blogs/lume/
# ↓追加
layout: layouts/blog.njk
---

最後にSCSSの変換やコードハイライト設定をします。Lumeではこれらはとても簡単です。
ここでは以下プラグインを使います。

_config.tsを以下のように変更します。

import lume from "lume/mod.ts";
// ↓追加
import sass from "lume/plugins/sass.ts";
import prism from "lume/plugins/prism.ts";
import "npm:prismjs@1.29.0/components/prism-bash.js";

const site = lume();
// ↓追加
site.use(sass())
site.use(prism())

なんとこれだけです。たったこれだけでプラグインがCSS変換やコードハイライトをしてくれます。
もちろんプレビューしながら、変更の即時反映もやってくれます[4]

ここまでやった段階でサイトは以下のようになっています。

CSS applied

だいぶ見栄えが良くなりましたね。少し設定を追加するだけで本格的な静的サイトが構築できました。

Lumeプラグイン

プラグインは自作もできますが、多くのプラグインがLumeから提供されています。
まず、ここから自分に合うものがあるのかを探すのがお得です。

自作する場合も、これらのプラグインのソースコードを参考にするとかなり手早く作れると思います。

マークダウンパーサーをカスタマイズする

Lumeではマークダウンパーサーにmarkdown-itを使っています。
今回は実施していませんが、このmarkdown-itのカスタマイズやプラグイン拡張ができます。

markdown-itのカスタマイズやプラグインをLumeで使う場合は_config.tsを修正します。

例えば、マークダウン改行設定、markdown-itのFootNoteプラグイン(注釈機能)を利用する場合は以下のようにします。

import footNote from "npm:markdown-it-footnote@^3.0.3"; // npmレポジトリから取得
import { Options as MarkdownOptions } from "lume/plugins/markdown.ts";

const markdown: Partial<MarkdownOptions> = {
  options: {
    breaks: true // マークダウンの改行を<br>タグに変換
  },
  plugins: [ footNote ] // FootNoteプラグイン
};

const site = lume({}, { markdown });

Denoでnpmレポジトリが正式サポートされるようになったので適用は簡単です。

詳細は以下公式ドキュメントを参照してください。

まとめ

#

今回はLumeを使って簡単な静的サイトを作成してみました。
単純なHTML変換だけでなく、各種プラグインを利用することで簡単に本格的な静的サイトが作成できました。
実際に触ってみると、Eleventyに負けないほど高速かつ拡張もしやすく当サイトでも運用できそうだと思いました。

ここではごく一部の機能しか紹介できていませんので、次回以降で掘り下げていきたいと思います。


  1. あえていうならTypeScriptサポートがないことと、ドキュメントが分かりにくいことでしょうか。 ↩︎

  2. 本記事はmacOS(Apple Siliconプロセッサ)の環境で検証しています。 ↩︎

  3. https://mozilla.github.io/nunjucks/templating.html#safe ↩︎

  4. ただし_config.ts変更時はDEVサーバーの再起動が必要です。 ↩︎

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

recruit

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