JSON
Jade
gulp
pug

gulp-jade で JSON ファイルを変数に読み込む方法(gulp-pug v2 対応追記)

More than 1 year has passed since last update.

jade でサイトを作成していると、共通情報は外部ファイルにまとめて記述したくなります。やはり jade なので、外部ファイルは JSON 形式にまとめておきたいところですね。

先に結論

gulp-data を使いましょう。
gulp-jade に使い方も紹介されてます。

gulp-data を使わない方法

公式の方法に辿り着く前に、ろくすっぽ調べずに自己流で JSON データをパースしてました…。
果たしてこの方法に需要があるのかどうか分かりませんが、試行錯誤の時間を無為にするのも悔しいので、まあ、こんな方法もあるよーということで、晒しておきます。

site.json
{
  "name": "サイトタイトル",
  "root": "/"
}
demo.jade
//- パースしたJSONデータを格納するグローバル変数
- var data = {}

//- JSON 構文をパースしてグローバル変数の data にデータを格納する mixin
mixin json(name)
  - var oldbuf = buf
  - buf = []
  block
  - data[name] = JSON.parse(buf.join(''))
  - buf = oldbuf

//- 外部 JSON 情報の読み込み
+json('site')
  include site.json

//- 呼び出し
h1: a(href=data.site.root) #{data.site.name}

解説

jade 標準出力を横取りして JSON をパースしてます。
最後に読み込んだ JSON が標準出力されないよう、バックアップしていた buf を書き戻してます。 buf は jade の mixins で使われている内部変数ですので、あまり行儀の良いやり方ではありませんが…

強いてこの方法の利点を挙げれば

  • gulpfile.js に 設定ファイルの記述なしに jade の構成ファイルの記述内で完結できる
  • gulp-data が何らかの理由により使えない環境の代替となる

と言ったところでしょうか。

gulp-pug v2 対策(2016年6月23追記)

jade は商標の問題から、pug に名前が変わりました。また、2016年6月23時点で v2.0 がベータ版リリースされていますが、v1.11から いろいろと内部構成が変わっていて、前述の mixin で横取りする方法が使えなくなりました。

素直に gulp-data を使った方が良さそうですが、ページ毎に適用する JSON ファイルを変更するような運用にしたいので、JSON ファイルの指定は gulpfile.js ではなく、pug ファイル側で指定したいところです。
pug 自体に外部 JSON ファイルをパースする機能があれば良いのですが、残念ながら現時点では自前で用意するしかなさそうです。

タスク側から pug に記述した JSON ファイルを取得する

pug 本体に手を加えるのは時間がかかりそうなので、手っ取り早く gulpfile.js のタスク処理側でカバーします。
ページ側に特定書式コメントの JSON ファイルのパスを指定しておき、タスクの gulp-data 経由で JSON ファイルを読み込むようにします。

pug コメントの後に続けて data path/to/filename.json と記述するルールとします。

demo.pug
//-data site.json

//- 呼び出し
h1: a(href=data.site.root) #{data.site.name}

pug コンパイルのタスクで、前述の JSON パスコメントを検知して、オブジェクトとして取り込むように、以下のように記述します。

gulpfile.js
'use strict';

var gulp = require('gulp');
var pug  = require('gulp-pug');
var data = require('gulp-data');

gulp.task("pug", function(){
  return gulp.src("./*.pug")
    .pipe(data(function(file) {
      var json = {};
      String(file.contents).split("\n").forEach(function(line) {
        if(line.match(/^\/\/\-\s*?data\s+?((\w+)\.json)$/)) {
          json[RegExp.$2] = require("./" + RegExp.$1);
        }
      });
      return { data: json };
    }))
    .pipe(pug({
      pretty: true
    }))
    .pipe(gulp.dest("./"))
   ;
});

これで 指定した JSON ファイルの内容を data.[ファイル名] のデータとして pug から参照できるようになりました。