やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

Zolaでextendsを使う

 フレームワークのようにベースとなるHTMLをつくる。

成果物

extends

 ベースとなるHTMLをつくり、その内側の一部分だけ変更したいときがある。そのときにextendsを使う。

templates/base.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
{%- block head %}{% endblock -%}
</head>
<body>
{%- block content %}{% endblock -%}
</body>
</html>

 headcontentというブロック要素が可変部分である。

{%- block head %}{% endblock -%}
{%- block content %}{% endblock -%}

 これを各テンプレートごとに少しずつ変えて書く。

  • index.html
  • section.html
  • page.html

templates/index.html

{% extends "base.html" %}

{%- block head %}
<title>{{ config.title }}</title>
{% endblock -%}

{%- block content %}
<h1>{{ config.title }}</h1>
<p>{{ config.description }}</p>
{% endblock -%}

 まずはファイルの先頭で{% extends "base.html" %}する。

 つぎにベースで定義したblock要素に書き出す内容を書いていく。

templates/section.html

{% extends "base.html" %}

{%- block head %}
<title>{{ section.title }} | {{ config.title }}</title>
{% endblock -%}

{%- block content %}
<ul>
{% for page in section.pages %}
<li><a href="{{ page.permalink }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
{% endblock -%}

templates/page.html

{% extends "base.html" %}

{%- block head %}
<title>{{ page.title }} | {{ config.title }}</title>
{% endblock -%}

{%- block content %}
{{ page.content | safe }}
{% endblock -%}

気に食わない点

  • include, import, extendsを使い分けねばならない
  • {% block * %}{% endblock * %}は必須で冗長

 可読性が低い。パッと見よくわからない。以下のように短く書きたかった。

base.html

<head>{$ head $}</head>
<body>{$ content $}</body>

 継承する側も以下のように短く書きたかった。

index.html

{$ base.html $}

$head
<title></title>

$content
<h1></h1>

マクロを隠しインクルードする技はextendsで使えない

 以下のようなマクロを作ったとする。

templates/macro/footer.html

{% macro footer() %}
<footer>© 2021 {{ config.extra.author }}</footer>
{% endmacro footer %}

 マクロ呼出だけをテンプレートにする。

templates/include/footer.html

{% import "macro/footer.html" as macro %}
{{ macro::footer() }}

 マクロ呼出テンプレをベーステンプレでインクルードする。

templates/base.html

{%- include "include/footer.html" %}

 ベースをほかのテンプレで継承する。

templates/index.html templates/section.html templates/page.html

{% extends "base.html" %}

 実行するも、エラーになる。

zola serve
Failed to build the site
Error: Failed to render page '/tmp/work/0/ytyaru-zola/content/archive/index.md'
Reason: Failed to render 'page.html' (error happened in 'base.html').
Reason: Macro namespace `macro` was not found in template `base.html`. Have you maybe forgotten to import it, or misspelled it?

 「macroというマクロ名前空間が見つからない」と怒られた。おそらく「importはファイルの先頭に書かねばならない」ルールに抵触したせいだろう。今回のテンプレではインポートがファイルの途中に書き出されてしまう。以下のように。ファイルの先頭にないせいで正しくインポートできず、マクロ名前空間も存在しない。よって本件のエラーになったものと推測する。

<!DOCTYPE html>
<html>
...
{% import "macro/footer.html" as macro %}
{{ macro::footer() }}
...
</body>
</html>

 今回わかったことは以下。

  • インポートとマクロ呼出は直接ベース(extends元)に書かねばならない

 それだとゴチャゴチャになるんだよなぁ。それを避けたくてマクロ呼出をインクルードする技を使ったのになぁ。

 残念。

include, macro(import), extendsのちがい

フレームワークにすべき部分はどこか?

 その答えは全ページに共通している部分だ。かなり限られていると思う。<html><body>など必須の要素のみが対象だ。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
{%- block head %}{% endblock -%}
</head>
<body>
{%- include "include/header.html" %}
{%- block content %}{% endblock -%}
{%- include "include/footer.html" %}
</body>
</html>
  • lang属性
    • <html lang="ja">のように言語を指定するのは多言語対応しているサイトのみでいい
      • 古い記法:```
    • Googleは代わりにhreflang属性を使っている
      • <link rel="alternate" hreflang="lang_code" href="url_of_page" />

これはページごとに変わりうる

メタデータ

 ファビコンやビューポートなら変わらないかもしれない。

<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="favicon.svg">

 個人サイトなら著者も同じだろう。

<meta name="author" content="{{ config.extra.author }}">

 タイトル、説明はほぼ違う。

<title>{{ page.title }} | {{ config.title }}</title>
<meta name="description" content="{{ page.description }}">

 変数を使えば共通化できるかもしれないが、pagesectionなど変数自体が別物だと統一できない。

<title>{{ section.title }} | {{ config.title }}</title>
<meta name="description" content="{{ page.description }}">

 条件分けすれば共通化できるか? 未確認。

<title>
{%- if page and page.title %}{{ page.title }} | {% endif -%}
{%- if section and section.title %}{{ section.title }} | {% endif -%}
{%- if config and config.title %}{{ config.title }}{% endif -%}
</title>

 CSSは変わりうる。メインコンテンツ次第。

<link rel="stylesheet" href="/css/black.css"">
<link rel="stylesheet" href="/css/white.css"">

<link rel="stylesheet" href="/css/mobile.css" media="screen and (max-width: 899px)">
<link rel="stylesheet" href="/css/pc.css" media="screen and (min-width: 900px)">

 メインコンテンツ。これはもう絶対に違う。パターン化できたとしてもセクション単位。サイト全体ではほぼ間違いなく変わる。[zola][]においてもindex.html, section.html, page.htmlの3種類の異なるテンプレートがあるくらいだ。最低でも「記事ページ」とその「一覧ページ」の2種類は必要だ。それらの内容が同じわけがない。

<main><article><h1>{{ page.title }}</h1><p>{{ page.description }}</p>{{ page.content | safe }}</article>bbbbbbbbbbbbb</main>
<aside>
<nav class="pagination">
{% if page.earlier %}<a class="previous" href="{{ page.earlier.permalink }}">‹ {{ page.earlier.title }}</a>{% endif %}
{% if page.earlier and page.later %} {% endif %}
{% if page.later %}<a class="next" href="{{ page.later.permalink }}">{{ page.later.title}} ›</a>{% endif %}
</nav></aside>
<aside><!-- ad --></aside>

 <main>/<aside>/<article>の大枠くらいは共通できそうな気がする。

<main><article><h1>{{ page.title }}</h1><p>{{ page.description }}</p>{{ page.content | safe }}</article></main>

 よくある前後記事リンク。これは欲しいときとないほうがいいときがありそう。

``html

 メイン以外。広告とかサイドバーなど。でもこれって、そもそも存在しないほうが嬉しいものなんだよね。共通化して全ページで出したら邪魔すぎて殺意をいだくやつ。

 もし`<body>`タグ内で全ページ共通するところがあるとすれば`<header>`や`<footer>`くらいだろう。

* `about`
* `author`
* `archive`
* `feed`
* `sitemap`
* `search`
* `language`
* `style`
* `Github Repository`
* `twitter`
* `copyright`
* `license`
* `Site Policy`

 パンくずリストは階層によって変わる。なので全ページ共通にはできない。マクロを使えば共通化できるかもしれないが、今の知識ではわからない。

 こうして考えてみると、以下のような問題がある。

* 共通化できるか?
* どうやって共通化する?: `include`, `macro`(`import`), `extends`

 そもそも共通化できるかどうかわからない。その答えにたどりつくには[zola][]や[tera][]に精通している必要がある。そして、それができているなら、共通化する手段についても当たりがつく。

 結局、[zola][]や[tera][]を学ぶしかない。


* `<html>`
* `<head>`
    * `<meta charset="utf-8">`
    * `<title>{{ page.title }} | {{ config.title }}</title>`
    * `<meta name="description" content="{{ page.description }}">`
    * `<meta name="author" content="{{ config.extra.author }}">`
    * `<meta name="viewport" content="width=device-width, initial-scale=1">`
    * `http-equiv`
        * `<meta http-equiv="content-language" content="ja">`
            * `<html lang="ja">`が正しい
                * べつにいらない
        * `<meta http-equiv="default-style" content="default.css">`
    * OGP
        * `<meta property="og:title" content="ページタイトル">`
        * `<meta property="og:type" content="article">`
        * `<meta property="og:site_name" content="サイト名">`
        * `<meta property="og:url" content="ページURL(絶対パス)">`
        * `<meta property="og:image" content="ページOGP画像パス(絶対パス)">`
        * `<meta property="og:description" content="ページ説明文">`
        * https://ogp.me/
            * `og:audio`
            * `og:video`
            * `og:image`
            * `og:type`
                * `music.song`
                * `music.album`
                * `music.playlist`
                * `music.radio_station`
                * `video.movie`
                * `video.episode`
                * `video.tv_show`
                * `video.other`
                * `article`
                * `book`
                * `profile`
                * `website`
                * ``
                * ``
                * ``
                * ``
                * ``
                * ``
                * ``
                * ``
                * ``
                * ``
            * ``
            * ``
            * ``
            * ``
            * Audio
                * `og:audio`
                * `og:description`
                * `og:determiner`
                * `og:locale`: `ja_JP`
                * `og:locale:alternate`: `en_US`
                * `og:site_name`
                * `og:video`



    * `<>`
* `<body>`

# 所感

 

# 対象環境

* <time datetime="2021-08-02T17:28:01+0900" title="実施日">2021-08-02</time>
* [Raspbierry pi](https://ja.wikipedia.org/wiki/Raspberry_Pi) 4 Model B
* [Raspberry Pi OS](https://ja.wikipedia.org/wiki/Raspbian) buster 10.0 2020-08-20 [※](http://ytyaru.hatenablog.com/entry/2020/10/06/111111)
* [bash](https://ja.wikipedia.org/wiki/Bash) 5.0.3(1)-release

$ uname -a Linux raspberrypi 5.4.83-v7l+ #1379 SMP Mon Dec 14 13:11:54 GMT 2020 armv7l GNU/Linux