copy_people copy_things copy_matter ttl_topics ico_blank ico_facebook ico_twitter ico_hatebu ico_index

2017/10/23

gulp+Nunjucksことはじめ

INDEX

    こんにちは。
    エンジニアのtsubouchiです。

    ブログ初投稿の今回のテーマは HTMLテンプレートエンジン Nunjucks です。

    度々社内のエンジニア間で話題にあがるものの、手をつけていなかった「HTMLテンプレートエンジン」。
    今回良い機会があり、はじめてみることにしました。

    Nunjucks とは?

    A rich and powerful templating language for JavaScript.

    mozilla製の…リッチでパワフルなテンプレートエンジンです。

    Nunjucks以外に
    Pug
    Panini
    も検討しましたが、Pugは独自記法のため/PaniniはPugやNunjucksに比較して関数が少ないため、今回は見送りに。

    なお、ビルドツールには gulp を使用します。

    1.インストール

    3つのgulpプラグインを使用します。

    $ npm install gulp-nunjucks-render --save
    $ npm install gulp-html-beautify --save
    $ npm install gulp-data --save

    gulpでのNunjucksのレンダリングには gulp-nunjucks-render を使用します。
    gulp-data はデータを各ファイルに引き渡す、
    gulp-html-beautify はHTMLを整形する目的で入れています。

    2.gulpfile.js

    gulpfile.js

    var
    gulp = require("gulp"),
    nunjucksRender = require('gulp-nunjucks-render'),
    data = require('gulp-data'),
    htmlbeautify = require('gulp-html-beautify');
    
    var beautify_options = {
        'indent_with_tabs':true
    }
    
    gulp.task('njk', function () {
        return gulp.src(['src/templates/**/*.njk', '!src/templates/**/_*.njk'])
            .pipe(data(function() {
                return require('./src/templates/_data/site.json'); //各ファイルに引き渡すデータ
            }))
            .pipe(nunjucksRender({
                path: ['src/templates/'] //njkファイルの基点になるパス
            }))
            .pipe(htmlbeautify(beautify_options)) //生成されたhtmlをきれいに
            .pipe(gulp.dest('htdocs/'));
    });
    

    3.ファイル構成

    直前にpaniniの検討をしていたこともあり、Paniniの構成を参考に作成しました。

    .
    ├── htdocs/...............生成されたファイル
    │   ├── recruit
    │   │   └── index.html
    │   └── index.html
    └── src/templates/
        ├── _data..............共通データ
        │   └── site.json
        ├── _layouts...........レイアウトファイル
        │   └── _parent.njk
        ├── _partials..........共通ファイル(ヘッダー/フッターなど)
        │   ├── _footer.njk
        │   └── _header.njk
        ├── recruit............各ページファイル
        │   └── index.njk
        └── index.njk..........各ページファイル
    

    4.各ファイル

    共通データ

    src/templates/_data/site.json

    {
        "data":{
            "sitename": "EVOWORX"
        }
    }
    

    レイアウトファイル

    src/templates/_layouts/_parent.njk

    <!DOCTYPE HTML>
    <html lang="ja">
    
    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    
    <title>{{ pagename }}{{ data.sitename }}</title>
    <meta name="viewport" content="width=device-width">
    
    <link rel="stylesheet" href="/css/common.css">
    {% block css %}{% endblock -%}
    </head>
    
    <body>
    {% include '_partials/_header.njk' %}
    
    <article>
        {% block contents %}{% endblock %}
    </article>
    
    {% include '_partials/_footer.njk' %}
    
    <script src="/js/plugins.js"></script>
    <script src="/js/common.js"></script>
    {% block js %}{% endblock -%}
    </body>
    </html>
    

    共通ファイル

    src/templates/_partials/_header.njk

    <header>
        <h1><a href="/">{{ data.sitename }}</a></h1>
        <nav>
            <ul>
                <li><a href="/recruit/">RECRUIT</a></li>
            </ul>
        </nav>
    </header>
    

    src/templates/_partials/_footer.njk

    <footer>
        <a href="#top">PAGE TOP</a>
        <p>© EVOWORX All rights reserved.</p>
    </footer>
    

    各ページファイル

    src/templates/index.njk

    {% extends '_layouts/_parent.njk' %}
    {% set pagename = '' %}
    
    {% block css -%}
    <link rel="stylesheet" href="/css/index.css">
    {% endblock %}
    
    {% block contents -%}
    <section>
        <h2>クリエイティブでコミュニケーションの進化をデザインする</h2>
        <p>クリエイティブとテクノロジーを駆使して、モノ・コト・ヒトをつなげ、新しい価値観を生み出すプロダクション・カンパニーです。</p>
    </section>
    {%- endblock %}
    
    {% block js -%}
    <script src="/js/index.js"></script>
    {% endblock %}
    

    src/templates/recruit/index.njk

    {% extends '_layouts/_parent.njk' %}
    {% set pagename = 'RECRUIT | ' %}
    
    {% block css %}{% endblock %}
    
    {% block contents -%}
    <section>
        <h2>RECRUIT</h2>
        <p>EVOWORXは、クリエイティブとテクノロジーを駆使して、モノ・コト・ヒトをつなげ、新しい価値観を生み出すプロダクション・カンパニーです。</p>
        <p>お客様が大切にしているブランドや商品の価値を少しでも高めるために、コンテンツや仕組み作りを一緒に考えていけるプロフェッショナルな人材を募集しています。</p>
    </section>
    {%- endblock %}
    
    {% block js %}{% endblock %}
    

    生成されたファイル

    htdocs/index.html

    <!DOCTYPE HTML>
    <html lang="ja">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    
        <title>EVOWORX</title>
        <meta name="viewport" content="width=device-width">
    
        <link rel="stylesheet" href="/css/common.css">
        <link rel="stylesheet" href="/css/index.css">
    </head>
    
    <body>
        <header>
            <h1><a href="/">EVOWORX</a></h1>
            <nav>
                <ul>
                    <li><a href="/recruit/">RECRUIT</a></li>
                </ul>
            </nav>
        </header>
    
        <article>
            <section>
                <h2>クリエイティブでコミュニケーションの進化をデザインする</h2>
                <p>クリエイティブとテクノロジーを駆使して、モノ・コト・ヒトをつなげ、新しい価値観を生み出すプロダクション・カンパニーです。</p>
            </section>
        </article>
    
        <footer>
            <a href="#top">PAGE TOP</a>
            <p>© EVOWORX All rights reserved.</p>
        </footer>
    
        <script src="/js/plugins.js"></script>
        <script src="/js/common.js"></script>
        <script src="/js/index.js"></script>
    </body>
    
    </html>
    

    htdocs/recruit/index.html

    <!DOCTYPE HTML>
    <html lang="ja">
    
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    
        <title>RECRUIT | EVOWORX</title>
        <meta name="viewport" content="width=device-width">
    
        <link rel="stylesheet" href="/css/common.css">
    </head>
    
    <body>
        <header>
            <h1><a href="/">EVOWORX</a></h1>
            <nav>
                <ul>
                    <li><a href="/recruit/">RECRUIT</a></li>
                </ul>
            </nav>
        </header>
    
        <article>
            <section>
                <h2>RECRUIT</h2>
                <p>EVOWORXは、クリエイティブとテクノロジーを駆使して、モノ・コト・ヒトをつなげ、新しい価値観を生み出すプロダクション・カンパニーです。</p>
                <p>お客様が大切にしているブランドや商品の価値を少しでも高めるために、コンテンツや仕組み作りを一緒に考えていけるプロフェッショナルな人材を募集しています。</p>
            </section>
        </article>
    
        <footer>
            <a href="#top">PAGE TOP</a>
            <p>© EVOWORX All rights reserved.</p>
        </footer>
    
        <script src="/js/plugins.js"></script>
        <script src="/js/common.js"></script>
    </body>
    
    </html>
    

    5.使用した関数

    だいぶ宝の持ち腐れですが…これまでHTMLテンプレートを使用していなかった身としては これだけでも十分便利でした。
    ほかにもたくさんの 関数 が用意されています。

    また、今回Pug/panini/Nunjucks すべてで地味に気になったのが「余白の処理」でした。
    どうしても生成されたHTMLファイルに余分な空行が生まれてしまう。。
    ウェブサーバーにアップして終了であれば気にしませんが、HTMLファイルが納品物の場合は気になりました。

    Nunjucksの対処法は こちら
    {% block contents %}{% endblock %}

    {% block contents -%}{%- endblock %}
    のように、{%や%}を{%-や-%}として前後の余分な空行を消すようです。

    6.エディタの設定

    最後に、エディタの設定について。

    拡張子.njkとシンタックスハイライトの紐付けをします。
    各エディタのハイライトは こちら にあります。

    Sublime Text3への設定は下記を参考にさせていただきました。
    Sublime Textで特定の拡張子にデフォルトのシンタックスを紐付ける


    今回は複数人でコーディングする案件なのでPugの独自記法がデメリットになりましたが、個人で組むあるいはメンバーに学習をお願いできるならPugを採用してみたいですね。
    独自記法もEmmetに似てるので、言うほど学習コストもあまりかからないような。

    Paniniは独自関数が作れるので、カスタマイズを重ねたら良いものができそうです。

    Nunjucksも、たくさんある関数を使いこなせたら、またご報告します。

    参考サイト

    CONTACT

    お仕事のご相談や、弊社についてのご質問や
    ご要望など、お気軽にお問い合わせください。

    View