みなさんは、大量にある静的Webサイトを制作するとき、どうしていますか?
昔だと、Dreamweaverのテンプレート機能を利用していたかもしれません。
最近、もりさんは、Node.jsとgulpで制作しています。
最初は、Sassやimageminのついでに、使っていましたが、テンプレートエンジンで生成すると、間違いが少ないので、気に入りました。
Swigの選択について
EJSというテンプレートエンジンも有名だったので、迷いました。
LaravelのBladeやSymfonyのTwigなどのPHPフレームワークのテンプレートエンジンが頭にあったので、Swigというテンプレートエンジンを採用してみました。
gulpでgulp-swigを選択
gulpで使いたかったので、gulp-swigを選択しました。 もしかしたら、gulpと普通のSwigでもできるかもしれませんが、試していません、すみません。
前提の条件
すでにNode.jsをインストールしている状態で始めます。 また、npm initやnpm install –save-dev package_nameなどは、適宜お願いします。
階層
階層は、以下ようなイメージで進めます。
project ├ app(制作データ) │├ template(template用html) ││└ template.html │├ next(下階層ディレクトリ) ││└ index.html(中ページ) │└ index.html(トップページ) └ dest(納品データ)
Swigを利用したサンプルデータ
TwigやBladeを使ったことがあれば、それほど迷うことはないと思います。 もりさんは、以下のサイトで調べることが多いです。
Swig – A Node.js and Browser JavaScript Template Engine
各ファイルの中身の例
だいたい、こんな感じになるのではないでしょうか。
project/app/template/template.html
{% set site_name = 'サイト名' %} {% set site_description = 'サイト名の説明' %} <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>{% block title %}{{ site_name }}{% endblock %}</title> <meta name="description" content="{{ site_description }}"> <link rel="stylesheet" href="{{ path }}css/style.css"> <script src="{{ path }}js/plugin.js"></script> {% block javascript %}{% endblock %} </head> <body> {% block content %} {% endblock %} </body> </html>
project/app/index.html
{% extends "./template/template.html" %} {% set path = "./" %} {% block title %} {% parent %} - top {% endblock %} {% block javascript %} <script src="{{ path }}js/top.js"></script> {% endblock %} {% set news = [ {'date':'2017/08/28', 'title': 'タイトル1'}, {'date':'2017/08/29', 'title': 'タイトル2'}, {'date':'2017/08/30', 'title': 'タイトル3'}, {'date':'2017/08/30', 'title': 'タイトル4'} ]; %} {% block content %} <div class="container"> {% for n in news %} <section class="container__group"> <h1>{{ n.title }}</h1> <p>{{ n.date }}</p> </section> {% endfor %} </div> {% endblock %}
Swigの使い方
ここに書いたTagだけで、ほとんどのことはできると思います。
変数の展開とフィルター
変数をテンプレート内に展開するためには、以下のように書きます。
{{ path }} {{ n.title }} {{ n['date'] }}
また、変数に、フィルターを掛けて、変更することができます。 パイプ文字を繋げて、複数のフィルターをまとめて設定することもできます。
{{ stuff | striptags }}
Swig » Documentation » Filters
extends
テンプレートを読み込みます。 extendsで、大枠になる親テンプレートを読み込んで、部分的に書き換えたい箇所を、変数やBlockで書き換えていきます。
{% extends "./template/template.html" %}
block
親テンプレートで、blockを定義していると、後から上書きすることができます。
{% block content %}...{% endblock %}
set
変数を定義します。 すでに設定されている場合は、上書きになります。
{% set foo = 'anything' %}
if
条件分岐できます。
{% if obj == 'a' %} <p>a</p> {% elseif obj == 'b' %} <p>b</p> {% else %} <p>その他</p> {% endif %}
for
オブジェクトや配列をループします。 繰り返すコンテンツなどを生成することができます。 forの中では、loop.indexなどの変数にアクセスできます。
loop.index | 現在のindex(1から始まるindex) |
---|---|
loop.index0 | 現在のindex(0から始まるindex) |
loop.revindex | 終わりから始まる現在のindex(1から始まるindex) |
loop.revindex0 | 終わりから始まる現在のindex(0から始まるindex) |
loop.key | オブジェクトの場合、現在のkeyを取得できます。配列の場合、loop.indexと同じになります。 |
loop.first | loopの最初であれば、Trueになります。 |
loop.last | loopの最後であれば、Trueになります。 |
{% for n in news %} <section class="container__group"> <h1>{{ n.title }}</h1> <p>{{ n.date }}</p> </section> {% endfor %}
include
別ファイルのコンテンツを読み込むことができます。 その時、一緒に変数を入れることも可能です。
{% include "./include.html" with obj only %}
parent
親テンプレートのblockを継承して、現在のblockに追加できます。
{% block title %} {% parent %} - top {% endblock %}
gulp-swigの問題
実は、このまま書き出しを行うと、いくつか問題が発生しました。
- 変数などを定義したソースが、そのまま空いてしまう
- テンプレートだけを更新した場合、書き出しに工夫が必要
- htmの拡張子が、htmlになってしまう
そのあたりを考慮して、gulpfile.jsとgulpのプラグインを設定します。
変数などを定義したソースが、そのまま空いてしまう
一度、HTMLを圧縮し、それを整形して、余計な空きをなくします。 そのために以下のプラグインを導入します。
gulp-html-minifier | HTMLを圧縮します。 |
---|---|
gulp-prettify | HTMLを整形します。 |
テンプレートだけを更新した場合、書き出しに工夫が必要
gulp-changedで変更を監視し、Browsersyncで自動更新している場合、テンプレートを更新しても、変更を検知しないので、反映されません。
gulp-ifを利用して、テンプレートを更新したときは、変更を検知せず全て書き出しを行います。
また、Swigのcacheをfalseにします。
gulp-if | 条件分岐でフローを制御します。 |
---|
htmの拡張子が、htmlになってしまう
普通はhtmを使うことなどないと思いますが、既存のコンテンツの追加修正で、htmのファイルのままでいたいのに、htmlになってしまいます。
gulp-renameを利用して、拡張子をhtmに戻します。
gulp-rename | ファイル名変更します。 |
---|
できたgulpfile
gulpfile.jsの中身は、こんな感じです。 できるだけ、Swigに関係しているものだけ切り取っています。
gulpfile.js
var gulp = require('gulp'), rename = require('gulp-rename'), gulpif = require('gulp-if'), browser = require('browser-sync'), plumber = require('gulp-plumber'), changed = require('gulp-changed'), runSequence = require('run-sequence'), swig = require('gulp-swig'), prettify = require('gulp-prettify'), htmlmin = require('gulp-html-minifier'); var paths = { swig :['app/**/@(*.html|*.htm)','!app/template/**'], dist :'./dest' }; var watch = { swig :paths.swig, layout:'app/template/**' }; var layoutCompile; gulp.task('compile', function () { var flag = false; return gulp .src(paths.swig) .pipe(plumber()) .pipe(gulpif(!layoutCompile, changed(paths.dist))) .pipe(rename(function (path) { if (path.extname === '.htm'){ flag = true; }else{ flag = false; } })) .pipe(swig({ defaults: { cache: false } })) .pipe(rename(function (path) { if (flag){ path.extname = '.htm'; } })) .pipe(htmlmin({collapseWhitespace: true})) .pipe(prettify({indent_size: 4})) .pipe(gulp.dest(paths.dist)) .pipe(browser.reload({stream:true})); }); gulp.task('watchSwig', function() { layoutCompile = false; }); gulp.task('watchLayout', function() { layoutCompile = true; }); gulp.task('watch', function() { gulp.watch(watch.swig, ['watchSwig', 'compile']); gulp.watch(watch.layout, ['watchLayout', 'compile']); }); gulp.task('server', function() { browser({server: {baseDir: paths.dist}}); }); gulp.task('default', function(callback) { layoutCompile = false; runSequence( 'compile', 'server', 'watch', callback ); });
まとめ
これで、100ページくらいならさくっと作れます。
ただ、ページ数が多くなると、テンプレートを更新する場合、時間がかかるようになります。
個別にページを保存して確認し、タイミングで一気に書き出すようにしましょう。
エムディエヌコーポレーション (2016-06-01)
売り上げランキング: 49,123
コメント