テンプレートエンジンの調査をしていたら何故かSSGを調べていて、偶然見つけたRust製のZolaが気になったので公式サイトのサンプルブログの作成(First Steps with Zola)を試してみます。Zolaのバージョンは0.14.1です。ちなみにSSGを触るのは初めてです。
概要
ZolaはRust製のSSGで、テンプレートエンジンはRust製のTeraが使われています。TeraはPythonのテンプレートエンジンJinja2やDjangoテンプレートをインスパイアして作られたとのことです。LiquidやTwigにも似ています。
コンテンツはCommonMarkで記述するようです。CommonMarkを調べてみるとMarkdownの仕様がカッチリしていないので作られた感じでした。
https://commonmark-ja.readthedocs.io/ja/latest/
https://qiita.com/Prof-Cheese/items/9629438b06aacc068c98
インストール
Zolaは様々な環境にインストールできるみたいです。詳しくは公式サイトへ。
Windowsユーザーなので WSL2 Ubuntu-20.04 にインストールすることにしましたが、色々とハードルがあり試行錯誤して多くの時間を使いました。結果的に手間が少ないのはHomebrewをインストールしてZolaをインストールするのがいいと思います。
もしSnapやDockerを動かせる環境にしているのであればそちらが早いです。
Homebrewのインストール
公式サイトのLinux用ドキュメントの通りですが、WSL2 Ubuntuにインストールするので以下のコマンドで必要なパッケージをインストールします。
sudo apt-get install build-essential procps curl file git
本体のインストールは公式サイトのコマンドを実行します。少々長いので待ちます。
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
PATHの解決も公式サイトに書いてあるやつです。
test -d ~/.linuxbrew && eval "$(~/.linuxbrew/bin/brew shellenv)"
test -d /home/linuxbrew/.linuxbrew && eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
test -r ~/.bash_profile && echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >>~/.bash_profile
echo "eval \"\$($(brew --prefix)/bin/brew shellenv)\"" >>~/.profile
PATHを通したら以下のコマンドでbrewが実行できるか確認します。
exec $SHELL -l
brew -v
# 以下のように表示されれば完了です
# Homebrew 3.2.16
# Homebrew/homebrew-core (git revision 27200f29f23; last commit 2021-10-18)
Zolaのインストール
brewのインストールが完了したのでzolaをインストールします。
brew install zola
zola
# 以下のように表示されれば完了です
# zola 0.14.1
# Vincent Prouillet <hello@vincentprouillet.com>
# A fast static site generator with everything built-in
#
# USAGE:
# zola [OPTIONS] <SUBCOMMAND>
# ...
サンプルブログを作る
公式サイトの内容を少し改変して記載しています。
プロジェクトの作成
適当なディレクトリで以下のコマンドでプロジェクトを作成します。
zola init myblog
## コマンドを実行すると問い合わせがでるので、デフォルトっぽい大文字の方を選択しました。
# 適当にURLを設定
> What is the URL of your site? (https://example.com): https://myblog.hakooji.local
# Sassを使うか?
> Do you want to enable Sass compilation? [Y/n]: Y
# コードブロックでシンタックスハイライトを使用するか?
> Do you want to enable syntax highlighting? [y/N]: N
# JavaSciprtの検索インデックスを出力するか?
> Do you want to build a search index of the content? [y/N]:N
以下の構成でプロジェクトが作成されました。
├─ config.toml # 設定ファイル
├─ content/ # コンテンツディレクトリ
├─ sass/
├─ static/
├─ templates/ # テンプレートディレクトリ
└─ themes/
設定ファイルはconfig.toml
で、プロジェクト作成時の問い合わせはこのファイルに書かれています。公式の設定ファイルを見た感じでは、htmlファイルのminifyやリンク切れのチェック、多言語に対応しているようです。
最終的に以下の構成を作成したらサンプルサイトの出来上がりです。
├─ config.toml
├─ content/
│ └─ blog/
│ ├─ _index.md
│ ├─ first.md
│ └─ second.md
├─ sass/
├─ static/
├─ templates/
│ ├─ base.html
│ ├─ blog-page.html
│ ├─ blog.html
│ └─ index.html
└─ themes/
開発サーバーの起動
Zolaは開発サーバーを起動したまま作業するので、config.toml
ファイルがあるディレクトリに移動してサーバー起動コマンドを実行します。
cd myblog
zola serve
# 実行すると以下が表示されます
Building site...
...
Web server is available at http://127.0.0.1:1111
起動があまりにも早くてビックリしましたが、出力されたURLhttp://127.0.0.1:1111
にアクセスするとWelcome画面が表示されます。次はホームページの作成です。
ホームページの作成
ホームページを作るには基盤となるテンプレートを作成します。template
ディレクトリにbase.html
を作成して以下の内容で保存します。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>MyBlog</title>
</head>
<body>
<section class="section">
<div class="container">
{% block content %} {% endblock %}
</div>
</section>
<footer>
{% block footer -%}
<p>This is Footer!</p>
{%- endblock %}
</footer>
</body>
</html>
同じディレクトリにindex.html
を作成して以下の内容で保存します。
{% extends "base.html" %}
{% block content %}
<h1 class="title">
This is my blog made with Zola.
</h1>
{% endblock %}
{% block footer -%}
{{ super() }}
<p>Append Text!</p>
{%- endblock %}
Teraはテンプレートを継承して構築ができます。index.html
の1行目{% extends "base.html" %}
は、継承するテンプレートを指定していて、この内容だと親テンプレートはbase.html
になります。
親テンプレートと子テンプレートのコードに{% block content %} {% endblock %}
と書かれている部分はブロックと言われ、任意のブロック名を付けることができます。親テンプレートのブロックを子テンプレートで置き換えたり、追記して構築を行っていきます。
子テンプレートの{% block footer -%}
内に{{ super() }}
とありますが、これは親テンプレートの内容を出力することができます。
例を挙げるなら親テンプレートでcssやjsブロックを作って、子テンプレートではページ専用のcssやjsを入れる感じです。
細かいところの話ですが、{% block footer -%}
というコードの最後に-
が付いています。Teraは区切り文字の{% %}
{{ }}
{# #}
と書いた部分はレンダリングすると空行になってしまうため-
を付けて削除します。ミニファイすれば関係ない話になりますが、知っておくと便利なこともあるはずです。
Zolaのサーバーを起動したままなので、ブラウザの画面は作成したindex.html
が表示されているはずです。
これでホームページは出来上がったので次はブログを作りましょう。
ブログの作成
ブログはcontent
ディレクトリにblog
ディレクトリを作成して、一覧の_index.md
と記事の_first.md
を作ります。
├─ content
│ └─ blog
│ ├─ _index.md #一覧
| └─ _first.md #記事
ブログ一覧の作成
blog
ディレクトリに_index.md
を作成して以下の内容で保存します。ファイル自体はMarkdownですが、 Front Matterと言われる+++
で囲まれた部分を作成してTOML形式で設定します。
+++
title = "List of blog posts"
sort_by = "date"
template = "blog.html"
page_template = "blog-page.html"
[extra]
subtitle = "extra can add variables."
+++
- title = 一覧に表示するタイトル。
- sort_by = 一覧のソート方法を指定します。
date
なので日付ソートになります。 - template = 一覧のテンプレートファイルを指定します。後で
templates
ディレクトリにblog.html
を作成します。 - page_template = 記事のテンプレートファイルを指定します。こちらも後で
templates
ディレクトリにblog-page.html
を作成します。 - [extra] = 任意の変数を追加できます。subtitleを追加しています。
次に一覧ページを表示するためtemplates
ディレクトリにblog.html
を作成します。
{% extends "base.html" %}
{% block content %}
<h1 class="title">
{{ section.title }}
<small>{{ section.extra.subtitle}}</small>
</h1>
<ul>
{% for page in section.pages %}
<li><a href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
<h3>section variable dump.</h3>
<p>{{ section | json_encode }}</p>
{% endblock content %}
blog.html
はbase.html
を継承して作成しました。_index.md
で設定したtitle
はsection
変数に格納されているのでsection.title
でアクセスでき、extra
に入れたsubtitle
はsection.extra.subtitle
でアクセスできます。
{% for page in section.pages %}...{% endfor %}
に関しては記事を作らないと表示されないので、あとで確認しましょう。
一応section
変数の中身を見るために{{ section | json_encode }}
を入れています。すべての中身が見たい場合は{{ __tera_context }}
です。
これで一覧テンプレートは完成なので、http://127.0.0.1:1111/blog/
にアクセスしてみてください。正常に表示されたでしょうか?
URLの/blog/
を変更したい場合は、ディレクトリcontent/blog
を content/blog2
のように変更するだけで反映されます。
次は記事の作成です。
ブログ記事の作成
blog
ディレクトリに_first.md
を作成して以下の内容で保存します。
+++
title = "My first post"
date = 2019-11-27
[extra]
subtitle = "testtest"
+++
This is my first blog post.
## h2
<h3>h3 tag.</h3>
*[Blog index.](../)*
+++
の後にMarkdownでコンテンツを記述していきます。一応確認のためにHTMLタグを書きましたが大丈夫なようです。
記事データができたので、次は記事テンプレートのblog-page.html
を作成します。
{% extends "base.html" %}
{% block content %}
<h1 class="title">
{{ section.title }}
<small>{{ section.extra.subtitle}}</small>
</h1>
<ul>
{% for page in section.pages %}
<li><a href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
<h3>section variable dump.</h3>
<p>{{ section | json_encode }}</p>
{% endblock content %}
こちらも一覧テンプレートと同様にbase.html
を継承して作成しました。{{ page.content | safe }}
のsafe
フィルターは、「変数は安全」という意味になり、HTMLをエスケープせずに出力します。Teraには色々なフィルターが準備されているので気になる方はこちらからどうぞ。
記事とテンプレートを作成したので http://127.0.0.1:1111/blog/
に記事リンクが表示されているはずなのでアクセスしてみましょう。
記事を追加する場合は、_first.md
を複製して_second.md
などの名称で保存するだけで、一覧が増えることが確認できるはずです。
ビルド
サイトが出来上がったので、ターミナルから以下のコマンドを実行してビルドします。
zola build
publicディレクトリにファイルが出力されたでしょうか?これでサンプルブログサイトの完成です!
まとめ
SSGを全く触ったことがないので良い物かは判断できませんでしたが、無事にサンプルブログサイトが構築できました。
もう少し深い部分に入ってくると構築に時間がかかる部分がでてくると思いますが、小規模のサイトであれば短い時間でサイトが作れる印象を受けました。色々ドキュメントを読むよりもテーマがいくつか準備されているので、これを利用して解析をしながら構築した方が早いかもしれないです。
気になる点を挙げるとするなら、Teraの構文と似ているテンプレートエンジンを使ったことがないと、そこそこ時間が取られるかもしれません。
Teraがインスパイアしているjinja2をそれなりに触った経験から言うと、シンプルな記述で構築が行えるテンプレートエンジンですが、シンプルが故に癖があります。ビルドインのフィルターや関数だけだと回りくどい実装しかできないことがあったり、動作しない場合の問題解決や調査に時間を取られることが多いです。でも素敵なテンプレートエンジンですよ!
最後にビルド速度が気になったのでシンプルなテーマのzola-picklesを入れて、適当な記事を2000件ぐらい複製して測定したら 1.7秒 ぐらいでした。マシンスペックやテンプレートの仕組み、サイト構成でかなり速度が変わってくるはずですが、普通に使うなら十分なのではと思いました。
SSGを普通のWebサイト制作に使えるかなー?とか考えながら構築を行いましたが、乗り越えるハードルはそこそこ多そうです。
コメント