webpackのみでpugを含めた開発環境を作ろうとしたとき、問題になりやすいのがmeta情報の出しわけかと思います。
webpackで環境を作った場合、pugもloader経由になるので個別にdataを渡しにくいのが問題になるためです。
この問題をどう解決しているかネットで探ると、出てくるのが二つのパターンだと思います。
パターン1 pugファイル上でJSONのキーを設定して出し分ける方法
こちらの記事にあるように各ページにjsonのキーを埋め込んで、JSONからデータを取得するもの
- var page = pagelist['pagelist'];
このパターン比較的スマートだと思うのですが、各ページに自分でキーを埋め込む必要性があるので、コピペでそのまま変更忘れなどのヒューマンエラーが発生する可能性があります。
gulp-dataだとこの辺を自動で解決できるので難を示す人もいるんじゃないでしょうか。
パターン2 globuleなどを使いHtmlWebpackPluginでdataにJSON情報を埋め込む方法
【脱gulp】webpackでpugを使う。jsonで一括ビルドも。
こちらの記事にあるように、各entryに対してHtmlWebpackPluginでJSONデータを埋め込んで取得すもの
documents.forEach((document) => {
const replaceJson = document.replace('_template', '_data').replace('.pug', '.json')
const json = require(replaceJson)
Object.keys(json).forEach((f) => {
const fileName = f
app.plugins.push(
new HtmlWebpackPlugin({
filename: `${dirName}/${fileName}.html`,
template: document,
data: json[f],
})
)
})
}
この方法だと動的に埋め込まれるので、パターン1のようなヒューマンエラーは無く一見よさそうに見えるのですが、これにも欠点があります。
webpackのentryにpugを全部突っ込むので、コンソールに大量のログが出ます。
自分も Webpackを頑張って設定して、すごい静的サイトジェネレータとして使おう を参考に作ったことあるのですが、ページが増えるほどビルドするたびに恐ろしいログが流れます(1ページ1行どころではないです。HtmlWebpackPluginを入れるとさらにヤバい事になります)。デプロイ位なら良いのですが開発中だとエラーを追うのも結構しんどいです。
pugを含める環境を作る場合は webpackだけでpugをビルドする環境を作る にあるような、entryするjsの中で pugをimportしてextructする形 にする方がお勧めです。
entryが少なくなり全体の流れるログをかなり減らす事が出来ます。
どちらも欠点があるので別の方法を紹介したいと思います。
パターン3 pug-html-info-loader を使用してpugのローカル変数からJSONで出し分ける方法
パターン1で各ページに自分で埋め込まなきゃいけなかったものを、自動で埋め込めるようにする方法です。
既存にあるpug系loaderだとパス情報をうまく取得する方法が見つからなかったので、pug-html-loaderをカスタマイズして pug-html-info-loader を作りました。
pug-html-loaderの代わりに使用すると、パス情報(pathInfo)をローカル変数として自動的にセットすることができます。
変更内容自体はpug-html-loaderに、ローカル変数を追加しているだけなので、使い方は一緒です。
pug-html-info-loaderのローカル変数で取得できるpathInfoの情報
例
optionsでbasePathをsrc/baseDir/の位置に設定した場合に
src/baseDir/first/second/page.pug で取れるpathInfoの情報
【 pathInfo.pug 】 → first/second/page.pug
【 pathInfo.html 】 → first/second/page.html
【 pathInfo.dir 】 → first/second/
【 pathInfo.parent 】 → second
【 pathInfo.basename 】 → page
【 pathInfo.htmlname 】 → page.html
【 pathInfo.pugname 】 → page.pug
この【 pathInfo.html 】などをキーにしたjsonなどを作成することで、動的にmeta情報や他に使用したい情報をpugから取得することが出来ます。他にもparentやbasenameをページのclassとして利用したりできると思います。
具体的なmetaの設定方法
各ページに設定するmetaのjsonを以下のような形で作ります。
【 global 】に共通のmeta情報
【 local [ pathInfo.htmlになるキー ] 】に個別のページmeta情報
{
"global": {
"title": "global title",
"description": "global description",
"og_url": "global og_url",
"og_image": "global og_image",
"og_siteName": "siteName",
"og_type": "website",
},
"local": {
"path/to/page1.html": {
"title": "Page1 title",
"description": "Page1 description",
"og_url": "Page1 og_url",
"og_image": "Page1 og_image"
},
"path/to/page2.html": {
"title": "Page2 title",
"description": "Page2 description",
"og_url": "Page2 og_url",
"og_image": "Page2 og_image"
}
}
}
webpackの設定
const path = require('path')
const metadata = require('./meta.json')
module.exports = {
module: [{
rules: [
{
test: /\.pug/,
use: [
'html-loader',
{
loader: 'pug-html-info-loader',
options: {
data: {
globalConf:metadata['global'],
localConf :metadata['local']
}, //meta.jsonのglobalとlocalをそれぞれの変数としてセットする
basePath: path.resolve(__dirname, 'src')
// 基準になるパスの位置をsrcフォルダに設定
}
}
]
}]
layout用のpugファイルを以下のようにします。
- var config = localConf[pathInfo.html] ? localConf[pathInfo.html] : globalConf ;
doctype html
html(lang='ja')
head
meta(charset='utf-8')
title #{config.title}
meta(name='description', content=config.description)
meta(property='og:title', content=config.title)
meta(property='og:site_name', content=globalConf.og_siteName)
meta(property='og:description', content=config.description)
meta(property='og:url', content=config.og_url)
meta(property='og:image', content=config.og_image)
meta(property='og:type', content=globalConf.og_type)
このように設定することで、以下のように出し分けることが可能になります。
【 localConf 】に【 pathInfo.html 】が設定されているページ → 個別meta情報
【 localConf 】に【 pathInfo.html 】が設定されていないページ → 共通のmeta情報
組み込んだサンプル
webpackのみでビルドする環境を作る(pug, sass, babel)で紹介されている環境に、
pug-html-info-loader でmeta情報を動的に出す方法で改造したものをgitに上げてあります。
触ってみたい方は こちら を試してみてください。
JSONのlocalになる部分をspreadsheetからGASでjsonを作れる仕組みをつくっておくと、より使いやすくなると思います。