ブログ

Nunjucksで恩恵を受けた話@変数編

こんにちは。エンジニアのシマです。
先日先輩がgulp+NunjucksことはじめでNunjucksを使った開発環境の設定について共有してくれました。

Nunjucks、共通メニューがある数ページ規模のサイトつくるときには、すごく便利です。
Pugと比べると、既存サイトのリニューアルなど今あるhtmlをベースにしたい場合は、htmlで書けるNunjucksのほうが移植も含めスピーディに開発できると思います( ˘ω˘)
今回は、先輩にのっかり実務で役立ったNunjucks TIPSを共有します。

条件分岐にはif文が便利

ページ毎に、表示項目の切り替え(サブメニューの内容、バナーの有無など)を行いたい!というときには、従来だとjsで項目生成や表示切り替えの対応をしていましたが、Nunjucksのif文を使うとhtml生成の段階で制御が可能になります。

【例】フッターバナーを出し分けてみる

①まずは先述の先輩の記事を参考にベースを作成していきます。 親テンプレと、それらを拡張した子テンプレ形式です。
②各ページの.njkファイルが用意できたら、その中で、ページを判別する用の変数をセットします。(汎用的に使いたかったので、「slug」としました。)

# src/templates/pageA/index.njk

{% extends '_layouts/_parent.njk' %}
{% set pagename = '' %}
{% set keyword = '' %}
{% set description = '' %}
{% set slug = 'pageA' %}    ←←←【ポイント】

{% block css %}<link rel="stylesheet" href="css/{{slug}}.css?18ss">{% endblock %}
# src/templates/pageB/index.njk

{% extends '_layouts/_parent.njk' %}
{% set pagename = '' %}
{% set keyword = '' %}
{% set description = '' %}
{% set slug = 'pageB' %}

{% block css %}<link rel="stylesheet" href="css/{{slug}}.css?18ss">{% endblock %}

③フッターテンプレートの中に、先ほど設定した「slug」の判定文を記述します。

# src/templates/_partials/_footer.njk

<ul class="footer__bnrlink">
{% if (slug == 'pageA') %}
  <li><a href=""><img src="バナー1の画像パス" alt="バナー1"></a></li>
  <li><a href=""><img src="バナー2の画像パス" alt="バナー2"></a></li>
{% elif (slug == 'pageB') %}
  <li><a href=""><img src="バナー2の画像パス" alt="バナー2"></a></li>
  <li><a href=""><img src="バナー3の画像パス" alt="バナー3"></a></li>
{% endif %}
</ul>

公式:https://mozilla.github.io/nunjucks/templating.html

④すると、出力結果は、下記のようになります。

# ページA

<ul class="footer__bnrlink">
  <li><a href=""><img src="バナー1の画像パス" alt="バナー1"></a></li>
  <li><a href=""><img src="バナー2の画像パス" alt="バナー2"></a></li>
</ul>

=============
# ページB

<ul class="footer__bnrlink">
  <li><a href=""><img src="バナー2の画像パス" alt="バナー2"></a></li>
  <li><a href=""><img src="バナー3の画像パス" alt="バナー3"></a></li>
</ul>

htmlで出し分けを出来て処理が散らかりません!テンプレエンジンの恩恵、あやかりました。

↑【例】フッターバナーを出し分けてみる、の別方法を考えてみる

先程の方法では、共通の親テンプレート(上位)を作り、その中で条件分岐を定義して出し分けをする仕組みになりますが、
この方法だとページが増えてきたときなどに毎回分岐を書かないといけないようになってしまいます。
そこで、各ページテンプレート(下位)にて上書きする場合は、{% block %}で親のブロックを呼び出し、拡張するという方法がとれます。
公式:https://mozilla.github.io/nunjucks/templating.html#template-inheritance

ただし上書きできるのは1つ上の階層のblockのみのようで、下記のような親子関係になっている場合、3レベルのindex.njkから1レベルにある_header.njk内のblockを呼び出して上書きすることはできませんでした。(コンパイルは通りました)

階層
(レベル)
フォルダ ファイル 備考
1 _partials _header.njk パーツファイル
2 _layout _parent.njk(親テンプレ) パーツファイルをinclude
3 _page _parent.njkindex.njk(ページテンプレ) 親テンプレのextend

なのでこういった場合は、_parent.njkを用意するのではなく、各ページテンプレートで_header.njkなどを個別によむ構成にしたほうが良いのかもしれません。

パスの指定は変数で楽々切り替え

共通部分の画像の読み込みなどは、ルートパス(ルート相対パス)で指定することで共通化が図れます。ただし、やむを得ない理由でテストサーバーと本番サーバーのパスが異なるなどという場合、ルートパスで指定しまうと意図したurlになってくれません、、ので、回避していきます。

ルートをパラメータで指定する

①コンパイル時にgulp-nunjucks-renderに読み込ませている、サイト情報をまとめた外部ファイル(site.json)に、親ディレクトリのルート(root)を設定しておきます。

# src/templates/_data/site.json

{
    "data": {
        "root": "/", // ←←←【ポイント】サーバーのルートパス設定部分
        "sitename": "sample",
        "siteurl": "http://www.sample.jp/xxxx/"
    }
}

②.njk内で、root情報を読み込んだかたちでパスを記述します。

# src/templates/404.njk

{% extends '_layouts/_parent.njk' %}
{% set pagename = '404 | ' %}
{% set keyword = '' %}
{% set description = '' %}
{% set slug = '404' %}

{% block css %}<link rel="stylesheet" href="{{ data.root }}404/css/404.css">{% endblock %}

{% block contents -%}

<div id="wrapper">
    <div class="container">
      <div class="box">
        <h1 class="sitename"><img src="{{ data.root }}404/img/404_logo.png" alt="404 Not Found"></h1>
      </div>
      <div class="box">
        <p class="text">誠に恐れ入りますが、再度アドレスを入力しても正しく表示されない場合、以下のページから該当する内容をお探しいただくかサイト内検索をご利用下さい。</p>
        <div><a href="{{ data.root }}"><img src="{{ data.root }}404/img/404_btn.png" alt="HOME"></a></div>
      </div>
    </div>
</div>

{%- endblock %}

{% block js %}{% endblock %}

あとは、切り替えが必要になった場合に、site.jsonのrootに追記したいパスをセットしてあげればOKです。

スタイル(css)もルートパス×変数で

併用テクとして、背景画像やアイコンなどの共通パーツをスタイルで読み込む場合も、ルートとなる変数を組み込んだ形でパスを記述しておけば安心です。

# src/scss/foundation/_vars.scss

$root: "/";
# src/scss/page/_404.scss

.wrapper {
    background: url(#{$root}common/img/ico_arrow.svg) no-repeat center;
}

あらかじめこのような予防線をはっておくと、後から置換に追われずに済みます。笑

・・・といった感じで、実践で使った小技の紹介でした。
また何か良い発見があれば共有したいと思います。では?