pugでWeb制作をしていて、
「ページごとのmeta情報をjsonなどで外部ファイル化して一元管理したい」
「できれば各ファイルでページ名を変数にセットするだけでそのページのmeta情報がheadにセットされるようにしたい」
と考えていたので、今回はそのやり方を解説します。なお、環境はgulpを使っています。
やりたいこと
- ページごとに違うmeta情報(title、keywords、descriptionなど)をjsonみたいな外部ファイルにまとめて一元管理したい
- 各ファイルの先頭でどのページのmeta情報を呼び出すかを指定するだけで、そのページのmeta情報がheadにセットされるようにしたい
ページの先頭でvar page = 'home';
と指定したらトップページのmeta情報がセットされる。var page = 'news';
と指定したらニュースページのmeta情報がセットされる、みたいなことをやりたいわけです。
pugでmeta情報をjsonで外部ファイル化する方法
jsonにこだわる必要はない
「jsonで一元管理する」と書きましたが、別にpugをjsonっぽく使うやり方でも全然大丈夫です。
pug内ではjsが使えるので、meta情報をオブジェクトに全部まとめるというやり方でもokです。というかjsonをpugで読み込めるようにするにはgulpfile.jsにモジュールを入れないといけないので、pugを使った方が正直ラクです。
meta情報がまとめられてるっぽい雰囲気を出したい人はjson、ラクしたい人はpugでいいと思います。僕はjsonでやりましたが、一応どちらの方法も解説します。
必要なファイル
以下の4つが必要です。headerやfooterは共通だと思うので各自用意してください。
- _pagedata.json(.pug):meta情報を一元管理
- _head.pug:共通headタグ(meta情報は変数にしておく)
- _template.pug:ページのテンプレート。先頭でどのmeta情報をセットするかを指定するのに必要
- hoge.pug:個別ページ
pugでjsonを読み込めるようにする
pugをjsonっぽく使いたい人はここは丸々飛ばして構いません。
jsonをpugで読み込むにはfs
とgulp-data
というモジュールが必要です。npmでインストールしましょう。
$ npm i -D fs
$ npm i -D gulp-data
そうしたらgulpfile.jsのpugのタスクにgulp-data
を入れてpugでjsonを読み込めるようにします。ディレクトリは各自書き換えてください。
const data = require('gulp-data');
const fs = require('fs');
gulp.task('pug', function () {
return gulp
.src(['./src/**/*.pug', '!./src/**/_*.pug'])
.pipe(plumber({ errorHandler: notify.onError('Error: <%= error.message %>') }))
.pipe(data(function (file) {//jsonを全pugファイルで読み込めるようにする
return JSON.parse(fs.readFileSync('./src/assets/inc/_pagedata.json'))
}))
.pipe(pug({ pretty: true }))
.pipe(gulp.dest(DIST));
});
.pipe(data(function (file) {}
の部分でファイルを読み込む処理をします。
return JSON.parse(fs.readFileSync('./src/assets/inc/_pagedata.json'))
jsonはそのままでは読み込めないのでJSON.parse()
でパースします。そうしたらfs.readFileSync()
で引数のディレクトリにあるファイルを読み込みます。
これで全てのpugファイルでjsonのデータが扱えるようになりました。
_pagedata.json
_pagedata.jsonにこんな感じでmeta情報をまとめていきます。
{
"meta": {
"home": {
"title": "home title",
"description": "home description",
"keywords": "home keywords"
},
"hoge": {
"title": "hoge title",
"description": "hoge description",
"keywords": "hoge keywords"
}
}
}
og:image
などが必要であれば追加していきましょう。
head内のtitleタグはmeta[page]['title']
という感じで変数にしておき、[page]
に"home"
や"hoge"
が入ることでmeta情報を切り替えるイメージです。
pugをjsonみたいに使いたい人はこんな感じで書けばokです。
-
var meta = {
"home": {
"title": "pugpugpug",
"description": "",
"keywords":""
},
"hoge": {
"title": "pughogepughoge",
"description": "",
"keywords":""
}
};
ページの先頭に-
を入れて以下の行は全部インデントして書けばファイル内を全部jsみたいに扱えます。jsonと違ってmeta
を変数で宣言することに注意しましょう。
ちなみに、「"meta"
の部分ってなくても大丈夫じゃね?」と思って試してみたのですが、ここがないとエラーになります(挙動がよくわからない…)。とにかく全部"meta": {}
の中に入れておけばokです。
_head.pug
head
meta(charset="utf-8")
title= meta[page]['title']
meta(name="viewport", content="width=device-width, initial-scale=1.0")
meta(name="description" content=meta[page]['description'])
meta(name="keywords", content=meta[page]['keywords'])
meta(http-equiv="X-UA-Compatible" content="IE=edge,chrome=1")
link(rel="stylesheet" href="./assets/css/style.css")
script(async defer src="./assets/js/script.js")
_head.pugではtitleやdescriptionなど、出力を変えたいmeta情報は変数にしておきます。
[page]
の部分が変数になっていて、ここを各ファイルの先頭で値を指定することでjsonに書いた特定のページのmeta情報を取得できます。
ちなみにpugはタグの後ろに=
をつけることでjsの変数を出力できます(title= meta[page]['title']
の部分)。
また、属性の値にjsの変数を使いたいときは値をクオーテーションで囲まずにそのまま変数を書けばokです(content=meta[page]['description']
の部分)。
_template.pug
各ページのテンプレートとなるファイルです。個別ページを作る際はこれをextends
します。
//- pugをjsonっぽく使う人はこの1行追加
include ./_pagedata
block page
doctype html
html(lang="ja")
include ./_head
body
.l-wrapper
include ./_header
block main
include ./_footer
block page
の部分が重要です!
ここにはextends
先のファイルでmeta情報を入れたいページ名をvar page = 'hoge'
という形で指定します(変数名は必ずpage
です)。変数page
に値がセットされると_head.pugに書いたmeta[page]['title']
のpage
の部分が確定するので、参照したいmeta情報をjsonから取得できるわけです。
なお、ページのメインコンテンツはblock main
としておき、extends
先で各ページごとに書けるようにします。
head、header、footerは大体のサイトで共通だと思うので外部化してincludeしておけばokです。
pugをjsonっぽく使う人は先頭で_pagedata.pugをinclude
しておきましょう(.pugは省略可能。_head.pugの先頭でinclude
してもok)。これでこのテンプレートをextends
したページ(個別ページ)で_pagedata.pugの値が取得できるようになります。
hoge.pug(個別ページ)
extends ./assets/inc/_template
block page
- var page = 'home';
block main
main.l-main
//- 以下メインコンテンツ
個別ページでは_template.pugを毎回extends
します。
block page
の部分でページ名を指定しましょう。前述の通りvar page = 'hoge';
という形でページ名を指定することで_head.pugのmeta[page]['title']
などのpage
の部分が確定し、jsonからmeta情報を取得できます。
page
の値を切り替えてみて出力されるmeta情報が切り替わればokです!
なお、メインコンテンツはblock main
の中に各ページごとに書いていきます。
これで変数page
の値を入れ替えるだけでjsonから取得するデータを切り替えられるようになりました!やった!
まとめ
pugでmeta情報を一元管理する方法は調べてもあまりいい方法がなかったのでエラーと格闘しながら色々いじってみました。
titleやdescription、keywordsなどはページによって違うのでなんとかしてうまく出力を変えられないかと試行錯誤していたら今回の方法にたどり着きました。
本当はblock
やextends
を使わない方法とかも探したんですがなかなか厳しい感じです(でも頑張れば無理ではなさそう?)
とりあえずmeta情報の出力分けはできたのでこのやり方がいいんじゃないかなと思います。参考になったら嬉しいです!