Closed20

Zola事始め作業ログ

anzanz

Scrap を使ってみたかったっていうのもあって作業ログとしてやってみる。

今のブログを Rust 製の SSG である Zola に移行しようと思っている。熱が冷めて断念する可能性もある。

https://www.getzola.org/

Documentに沿ってとりあえずは進めてみて、移行できそうかどうかも見る感じ。

anzanz

Overview - Getting Started を一通り通してやったので、サンプル記事が閲覧できるまでにはなった。

フォルダ構成は今の所こんな感じ

.
├── config.toml
├── content
│   └── articles
│       ├── _index.md
│       └── hoge.md
├── sass
├── static
├── templates
│   ├── articles
│   │   ├── list.html
│   │   └── page.html
│   ├── base.html
│   └── index.html
└── themes

ドキュメントと違って blog ではなくて、 articles になっているのは、今自分のブログのURL構成を意識した結果。

./templates/articles/list.html/articles/ にアクセスしたときに適用されるテンプレートで、
./tempaltes/articles/page.html/articles/hoge/ にアクセスしたときに適用されるテンプレートになる。

本格的に移行する時は、tampltes に tags というのも追加される感じになりそう。

anzanz

ここまででサクッと Hello World が終わった感じ。
ここからは、実際に移行するとしての検証をする。

  • トップページ
    • 直近の記事何件か -> 方針
    • タグクラウド(記事投稿数の多いタグ上位10件とかできたらいい。記事のタグは偏りがすごいので、最悪なくてもいい。それなりの投稿数があるタグは3つ4つぐらいだったはず) -> 方針
  • 記事リスト
    • articles/ でアクセスできるのでそれでよさそう。ページネーションは正直いらないかな
  • 記事ページ -> 方針
  • タグに紐づく記事リストページ -> 方針
    • 日本語タグの扱いがどうなるのかというのも気になるところ
      日本語のママURLにはならない。自動で変換される。既存のとは変わってしまうけど、記事ではなくてタグの記事リストなので、まぁ許容範囲内かな
  • Sitemap -> 方針
  • RSS(最悪なくてもいい)-> 方針

というあたりをどうやるのかというアタリをつける。
そしたらあとは、デザインを作り込んでいって、実際の記事を移行する段階にすすめる。これは粛々とやるだけなので、作業ログとしては不要そう。

anzanz

今のブログ記事のパスは /articles/20120514/title/ みたいに 日付-記事タイトル という形。
これを実現するためにはどうするのがよいだろうか?
これが変わってしまうとリダイレクトとかしなきゃならないので面倒。

anzanz

ローカルのフォルダ構成をあわせる方法

Zola は基本的にローカルのフォルダ構成と同じ構成で生成されるので、これを実現するために同じ構成で記事を作成したら可能。

content
└── articles
    ├── 20210513
    │   └── title
    │       └── index.md
    └── 20210514
        └── title.md

このどちらでも 日付-記事タイトル のパスで生成されることになる。

問題点

ローカルフォルダで合わせるやり方でいくつか気になったもの。

template 設定がめんどくさい問題。

この構成だと articles/_index.md で設定したテンプレートなどが効かないので、各記事の Front matter で設定する必要がある。

+++
title = "Post Title"
date = 2021-05-13
template = "articles/page.html"
+++

こういう感じ各記事で template の設定が必要になる。
Zola はフォルダがセクションという考えになるけれど、そのサブフォルダまでは親の設定が効かないらしく、template を個別に設定する必要があるという感じ。
問題点というよりかは、ただただめんどくさいという話。(VSCodeのスニペットとか使うので実際は問題にならんけれど)

記事リストが取れないかもしれない?

articles/ でアクセスできなくなるので、トップページで直近記事10件ほど取得するということができなくなりそう? 🤔

anzanz

Front matter の設定に subsections にという設定がるので、こちらで設定していけば、各記事でテンプレートの指定はしなくてなさそう。
だが、日付でフォルダ切ってるので記事書くたびにそちらに追記することになりそうなので、めんどくささがすごいかな? 🤔

anzanz

今回やりたいこととは関係ないけれど、ここによると、ファイル名に日付を入れてもそれは削除されて出力されるとのこと。

Example: The file content/blog/2018-10-10-hello-world.md will yield a page at [base_url]/blog/hello-world.

anzanz

Front matter で制御する方法

Front matter に path という設定があるのでそちらで制御する。

+++
title = "Title1"
date = 2021-05-14
path = "articles/20210514/title"
+++

こういう感じ。
これだと、フォルダ構成をあわせる必要はないのでローカルはこういう雑な感じでよさそう。

content
└── articles
    ├── _index.md
    ├── 20210513.md
    └── 20210514.md

ファイル名から内容を推察できるように、記事タイトルをファイル名にしたほうがいいかもしれない🤔
これだとちゃんと articles/ で記事リストにアクセスできるし、 artices/_index.md の設定が全記事に効くので、テンプレートの各ページ共通設定などは個別にしなくて済む。

問題点

path 設定がめんどくさい。

だけれど、ローカルフォルダで制御する場合はその分フォルダ名とファイル名を記述必要があるのが、path に代わるだけなので手間が増えるというわけではないので、問題点といえるものではない。

anzanz

記事URLを現状と合わせる方法で上記2つがざっくり考えられたけれど、後者でとりあえず決定でよさそう。
VSCode のスニペットなんかで

+++
title = ""
description = ""
date =
path = "articles/"
+++

というものを用意しておけばよいかな。

anzanz

トップページで直近記事を取得する方法は get_section() でパスを指定してリストを取得できるので、それを回していえけば一覧を作成できそう。

templates/index.html
{% block content %}
<h1 class="title">
  This is my blog made with Zola.
</h1>

{# 記事リスト取得 #}
{% set article = get_section(path="articles/_index.md") %}
{% for page in article.pages | slice(end=4) %}
<div>{{ page.title }} - {{ loop.index0 }}</div>
{% endfor %}

{% endblock content %}

{% if loop.index0 == 3 %} slice(end=4) が直近いくつまで取得するか制御している。
全件取得してくるのでこの制御が必要なのだけれど、可能であれば get_section() 部分で limit を指定する形で取得してきてもらいところではある。
リストに必要なのは記事のタイトルと日付ぐらいなので、get_section(path="articles/_index.md", metadata_only=true) と metadata_only を指定したくなるけれど、これだと上のままだと回せなくなってしまう。
なにかあるのだろうか... 🤔

ともあれ、これで直近記事リストも可能ということはわかった。

anzanz

タグ周りはなんとなくできたけど、タグクラウドとして、登録件数順に並び替えて表示するいい方法がわからない
get_taxonomy() をつかえばタグリストがとれる。
{% for tag in tags.items | sort(attribute="name")%} こうやれば、名前で並び替えはできる。
件数は tag.pages | length で表示はできる。これを並び替えの項目として指定したいのだけれど...さて?🤔という感じ。

anzanz

ちなみにタグを有効化するのは少し手順がいる。

config設定

config.toml に記述が必要

config.toml
# The URL the site will be built for
base_url = "https://blog.anzfactory.xyz"

# Whether to automatically compile all Sass files in the sass directory
compile_sass = true

# Whether to build a search index to be used later on by a JavaScript library
build_search_index = true

# taxonomies これがタグ有効にする
taxonomies = [
  { name = "tags", feed = true }
]

もし タグとは別にカテゴリーも使いたかったら

taxonomies = [
  { name = "categories", feed = true },
  { name = "tags", feed = true }
]

となる。自由に設定可能。

タグ用テンプレートの設定

templates
├── articles
│   ├── list.html
│   └── page.html
├── base.html
├── index.html
└── tags
    ├── list.html
    └── single.html

こういう感じで、templates の配下に list と single をおく。
それぞれ何を categories を設定したい場合は categories > list.html みたいな感じ

記事の Front matter で任意に設定

ここでやっと記事内に指定ができる(有効になる)
先に記事の Front matter で指定してもいいけど、特に何もおきない(笑)

+++
title = "Title12"
date = 2021-05-19
path = "articles/20210514/title12"
[taxonomies]
tags = ["rust", "zola"]
+++
anzanz

Tera のドキュメント

The values in the array must be a sortable type:

  • numbers are sorted by their numerical value.
  • strings are sorted in alphabetical order.
  • arrays are sorted by their length.
  • bools are sorted as if false=0 and true=1

と、sort に関する挙動の記述があり、

arrays are sorted by their length.

こちらで length を算出して指定するとばかり考えていたけれど、指定した attribute が配列の場合は勝手に length でやってくれるらしい。

Playground でちょっと確認してみたけれど、たしかにできた。

{% block title %}{% endblock title %}

{% for user in users | sort(attribute="items") | reverse -%}
{{ user.name }} - {{ user.items | length }}
{% endfor %}

sort は基本昇順なので reverse で降順にしてる。
これで user.items の配列の要素数が多い順に確かにソートできた。
なので、先のコメントの taxonomy で考えるとこういう感じ。

{% set tags = get_taxonomy(kind="tags") %}
{% for tag in tags.items | sort(attribute="pages") | reverse %}
<div>{{ tag.name }} - {{ tag.pages | length }}</div>
{% endfor %}

ちなみに、ハイフン -%} は出力結果の改行あたりに関係するものみたい。( {%- endfor %} とかもできる)
Tera template を通して出力されるものを html として綺麗に見えるようにしたいとかおもったら意識する必要がありそう? 🤔

anzanz

タグに紐づく記事リストは get_taxonomy_url() をつかえば遷移できるようになる。
使用感としては以下。

{% set tags = get_taxonomy(kind="tags") %}
{% for tag in tags.items | sort(attribute="pages") | reverse %}
<div><a href="{{ get_taxonomy_url(kind="tags", name=tag.name) }}">{{ tag.name }}</a> - {{ tag.pages | length }}</div>
{% endfor %}

日本語タグは自動的に何かしらの英字に切り替えられるようなので、get_taxonomy_url() をつかわず tag.name で直接 url 構築しようとすると遷移できない様になっちゃうので注意。
ということで日本語タグのURLは現状から変わってしまいそう(現状は日本語をそのままURLとしちゃってるので)

日本語がそのまま使えないにしてもslugとかでこっちで指定するようにできたらいいのだけれど...
個人開発 というタグだと ge-ren-kai-fa に置き換わるので一見して意味不明になっちゃう。

+++
[taxonomies]
tags = ["rust", {name = "個人開発", slug = "dev"}]
+++

記事の Front matter でとかしたさ。

anzanz

Sitemap は zola build したらそのまま生成されるので特に設定とかは必要なし

anzanz

RSS は設定( generate_feed = true )が必要。

config.toml
# The URL the site will be built for
base_url = "https://blog.anzfactory.xyz"

# Whether to automatically compile all Sass files in the sass directory
compile_sass = true

# Whether to build a search index to be used later on by a JavaScript library
build_search_index = true

# RSS(追記)
generate_feed = true

これを設定してあげたあとに zola build したら atom.xml が出力されるようになる

anzanz

ここまででだいたい検証おわり。
行けそうなので後は作り込んでいくのみ。
実際にやっていくなかで追加で何か調べたりしたら追記はしそうなので、ほぼclose状態だけれど実際に移行がおわってからcloseする

anzanz

Macro

トップページやタグで記事リストがあるなどなにか使いまわしたい場合は tera が macro 機能を提供しているのでそれを利用する。

Macros - Tera

ドキュメントのとおりだけれど、使い方は macro で定義して、使いたいテンプレートで import をして使いたい箇所で呼び出すという流れ。

定義

記事リストのアイテムというイメージで登録

templates/components/article_item.html
{% macro article_item(page) %}
<div>
  <div><a href="{{ page.path }}">{{ page.title }}</a></div>
  <p>
    {{ page.description }}
  </p>
</div>
{% endmacro article_item %}

使い方

使う方。トップページで使用する場合はこんな感じ。

templates/index.html
{% import "components/article_item.html" as macros %}
{% extends "base.html" %}

{% block content %}
<section>
  <h1>直近の投稿記事</h1>

  {% set article = get_section(path="articles/_index.md") %}
  {% for page in article.pages | slice( end = 5 ) %}
  {{ macros::article_item(page = page) }}
  {% endfor %}

</section>
{% endblock content %}

{% import "components/article_item.html" as macros %} でマクロをインポート
{{ macros::article_item(page = page) }} でインポートしたマクロの呼び出し。

複数テンプレートで使うようなものはこういう感じで用意しておくといろいろよさそう。

このスクラップは2021/05/23にクローズされました