omachizura

仕事メモ、役に立ったスキルをまとめています。


Front Matterでファイルごとに変数を持たせる

ejsやnunjucksなどのテンプレートエンジンを使用して、ホームページやブログを作成している場合、共通のテンプレートファイルに変数などを定義しておき、各ファイルではその変数に値をセットして、htmlを作成することになることが多いと思います。

例えば、以下のように各ページのタイトルや概要を変数にするテンプレートがあります。

※言語はnunjucksで説明しますが、他のテンプレートエンジンでも大体考え方は同じだと思います。

_layout.njk(nunjucks)

<!DOCTYPE HTML>
<html>

<head>
  <title>{{title}}</title>
  <description>{{description}}</description>
</head>

<body>
  <!--各ページのコンテンツ-->
  {% block content %}{% endblock %}
</body>
</html>

この時、各ファイルのtitleやdescriptionはどのように定義しておくか、という問題があります。

私は今まではjsonの別ファイルを作成し、そのファイルに全ページのタイトルや概要など、画面ごとに必要な変数を定義していました。

{
  "index": {
    "title": "トップページ",
    "description": "トップページです"
  },
  "sample1": {
    "title": "サンプルページ1",
    "description": "サンプルページ1です"
  },
  "sample2": {
    "title": "サンプルページ2",
    "description": "サンプルページ2です"
  }
}

しかしこのやり方では、1つのページを作成する際に、2つのファイルを編集しなければならなくなり、手間に感じていたので、別の方法を探すことにしました。

Front Matter

Front MatterとはJekyllという静的サイトジェネレーターで使用されているシステムです。

Front Matterを使えば、各ファイルに変数を定義して簡単に扱えるようになります。

各ページの先頭に以下のように---で囲って情報を定義します。

sample1.njk(nunjucks)

---
title: "サンプルページ1"
description: "Front サンプルページ1です"
---
{% extends '_layout.njk' %}
{% block content %}
<p>サンプルページ1のコンテンツです</p>
{% endblock %}

Front Matterの値を取得する

front-matterというモジュールを使用すれば、簡単にFront Matterで定義した情報を変数として取得できるようになります。

npm install front-matter

具体的には以下のように、取得します。content.attributesでFront Matterで定義した値をjson形式で取得できます。

var frontMatter = require('front-matter');

var content = frontMatter(ファイルの内容);
console.log(content.body); //Front Matterで定義した部分以外の内容
console.log(content.attributes); //Front Matterで定義した内容

gulpで使う

nunjucksをコンパイルするときに、Front Matterで定義した値をパラメータとして渡す必要があります。

gulp-nunjucks-renderでNunjucksをgulpでコンパイルする方法 で紹介したように、gulp-dataを使えばパラメータとして渡すことができます。

var gulp = require('gulp');
var nunjucksRender = require('gulp-nunjucks-render');
var data = require('gulp-data');
var frontMatter = require('front-matter');

gulp.task('compile', function(){
  gulp.src(['src/**/*.njk',
            '!src/**/_*.njk'])
    .pipe(data(function(file) {
      var content = frontMatter(String(file.contents));
      //Front Matterで定義した部分以外の内容をファイルの内容としてセットします
      file.contents = new Buffer(content.body);
      //Front Matterで定義した内容を返却します
      return content.attributes;
    }))
    .pipe(nunjucksRender())
    .pipe(gulp.dest('dst'));
});

Front Matterというシステム自体あまり知られていないのかもしれませんが、作成日や更新日などの情報も持つようにすれば、いろいろと便利に使えそうです。