前回はGulpで利用するテンプレートエンジンのEJSをご紹介いたしました。

EJSの他に、Gulpで利用できるテンプレートエンジンにはPugというものが有名なようなので、試しに使ってみました。
Pugとは
Pug(旧Jade)はHTMLを書くためのテンプレートエンジンで、JST (JavaScript Templates) の一つです。Pugは「.pug」という拡張子のファイル内でHTMLのようにタグで囲まず、改行やインデントによってページを作っていきます。Pugを利用するには「Node.js」が必要になります。PugにはGulp用のPugがあり、Gulpで使うことができます。
Pugで何ができるか
- ループや条件分岐。
- 共通ファイルの読み込み(インクルード)やパラメータの引き渡し。
- JavaScriptと同様に、数、文字列、配列、オブジェクトなどを扱える。
- htmlファイルへの出力。
gulp-pugを導入する
Pugを利用するには「Node.js」が必要なので前もってインストールしておきます。「Node.js」の導入は「Node.jsを導入する」を参照してください。
gulp-pugをインストールする
今回、PugはGulpで利用するので、下記のコマンドを入力してgulp-pugをインストールします。
npm i -D gulp-pug
gulpfile.jsに下記の記述をし、pugを利用できるようにします。
var pug = require("gulp-pug");
gulpfile.jsにgulp-pugのタスクを記述する
次にgulpfile.jsにgulp-pugのタスクを記述します。
//Pug(テンプレートエンジン)
gulp.task("pug", function() {
gulp.src(
["src/pug/**/*.pug",'!' + "src/pug/**/_*.pug"] //参照するディレクトリ、出力を除外するファイル
)
.pipe(pug())
.pipe(gulp.dest("dest/")) //出力先
});
- 「”src/pug/**/*.pug”」はサブディレクトリも含めた「.pug」ファイルを参照。
- 「’!’ + “src/pug/**/_*.pug”」はサブディレクトリも含めた「_」が先頭についた「.pug」ファイルの出力(インクルードファイル)を除外。
- 「.pipe(gulp.dest(“dest/”))」で「dest」というディレクトリ以下にファイルを出力。
Pugを使う
Pugファイルを作成する
作業するディレクトリに手動でPugファイルを作成します。今回は「src/pug/」にindex.pugを作成しました。

Pugの記法
index.pugには下記のように記述しました。
doctype html
html(lang="ja")
head
meta(charset="utf-8")
title トップページタイトル
link(rel="stylesheet" href="css/style.css")
body
h1 トップページ
main
p トップページテキスト
Pugは基本的に一行で記述します。doctype htmlで宣言、改行とインデントで要素をネスト、要素の後ろに半角スペースで要素内のテキストとなります。
htmlとして出力する
htmlとして出力するには「gulpfile.js」がある階層で下記のコマンドを入力してhtmlを出力します。
gulp pug
すると、gulpfile.jsに記述した「.pipe(gulp.dest(“dest/”))」が動作し、「dest/」直下にindex.htmlが出力されます。

gulpやPugのバージョンにもよりますが、「base」プロパティを指定せずとも「src/pug/news/」にindex.pugと作成した場合、階層はそのままコピーされ、「dest/」に「news/index.pug」が出力されます。ディレクトリ階層がそのままコピーされない場合は、「base」プロパティを使用しましょう。

出力したhtmlは下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>トップページ</h1>
<main>
<p>トップページテキスト</p>
</main>
</body>
</html>
Pugで出力するhtmlはがデフォルトでminify化されるので上記のソースは整形しています。
共通ファイルをインクルードする
ヘッダーやフッターなどの共通部分をinclude文を利用して、複数のページで共通で使用することができます。
_header.pug(ヘッダー)
今回は「/src/pug/common/」に「_header.pug」として共通で使うヘッダーを作成しました。

ヘッダーの内容は下記のようにしました。
<header>
ヘッダー
</header>
_footer.pug(フッター)
今回は「/src/pug/common/」に「_footer.pug」として共通で使うフッターを作成しました。

フッターの内容は下記のようにしました。
<footer>
フッター
</footer>
index.pugにヘッダーとフッターをインクルードする
index.pugに下記のように記述します。
doctype html
html(lang="ja")
head
meta(charset="utf-8")
title トップページタイトル
link(rel="stylesheet" href="css/style.css")
body
include common/_header.pug
h1 トップページ
main
p トップページテキスト
include common/_.pug
- 「include common/_header.pug」でヘッダーをインクルード。
- 「include common/_footer.pug」でフッターをインクルード。
上記のインクルードを行った後、gulp pugコマンドを入力して、index.htmlの中身を見ると下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>ヘッダー</header>
<h1>トップページ</h1>
<main>
<p>トップページテキスト</p>
</main>
<footer>フッター</footer>
</body>
</html>
index.pugにインクルードしたヘッダーとフッターがindex.htmlに出力されています。
「src/pug/news/index.pug」に上記のインクルードを行う場合は、階層が一つ変わるので下記のように「../common/」となります。
- 「include ../common/_header.pug」
- 「include ../common/_footer.pug」
ifやforなど
Pugはifやforで判定や繰り返しなどを行うことができます。
if文
「- var」が変数となります。
- var myFlg = 1 if myFlg == 1 p 1番目 else if myFlg == 2 p 2番目 else p 3番目
「if myFlg == 1」によって1番目の要素が出力されます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>ヘッダー</header>
<h1>トップページ</h1>
<main>
<p>トップページテキスト</p>
<p>1番目</p>
</main>
<footer>フッター</footer>
</body>
</html>
記述した条件での要素の表示は下記のようになります。

for文
ifの時と同じようにfor文の前に半角ハイフンを記述します。中かっこは「{」で始め、「- }」で終わります。
ul
- for (var i = 1; i < 6; i++) {
li #{i}個目のli
- }
forで繰り返した分だけliが出力されています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>ヘッダー</header>
<h1>トップページ</h1>
<main>
<p>トップページテキスト</p>
<ul>
<li>1個目のli</li>
<li>2個目のli</li>
<li>3個目のli</li>
<li>4個目のli</li>
<li>5個目のli</li>
</ul>
</main>
<footer>フッター</footer>
</body>
</html>
記述した条件でのliの表示は下記のようになります。

jsonでタイトルやディスクリプションを出力する
jsonファイル
Pugはjsonを利用してtitleやdiscriptionの内容を出力させることができます。まずは下記のような内容でjsonを作成します。
{
"pages": {
"index": {
"id": "index",
"title": "トップページタイトル",
"description": "トップページディスクリプション"
},
"news-index": {
"id": "news-index",
"title": "ニュースページタイトル",
"description": "ニュースディスクリプション"
}
}
}
jsonファイルは「pages.json」として下記の階層に設置しました。

jsonをパースできるように下記の記述をgulpfile.jsに追記します。
var fs = require("fs");
gulp-data
Pugで外部のデータを扱うため、下記のコマンドを入力してgulp-dataをインストールします。
npm i -D gulp-data
インストールしたgulp-dataを使用するためにgulpfile.jsに下記の記述をします。
var data = require("gulp-data");
gulp.taskにpages.jsonを追加
作成したpages.jsonをPugに読み込むため、「return JSON.parse(fs.readFileSync(`./pages.json`));」を追記します。
gulp.task("pug", function () {
gulp.src(
["src/pug/**/*.pug",'!' + "src/pug/**/_*.pug"] //参照するディレクトリ、出力を除外するファイル
)
//追記
.pipe(data( file => {
return JSON.parse(fs.readFileSync(`./pages.json`));
}))
//ここまで追記
.pipe(pug())
.pipe(gulp.dest("dest/")) //出力先
});
index.pugにタイトルとディスクリプションの変数タグを埋め込む
index.pugの先頭にページを判定する変数、titleとdescription要素に変数タグを記述します。
- var pageId = "index"
doctype html
html(lang="ja")
head
meta(charset="utf-8")
title #{pages[pageId].title}
meta(name="description" content=pages[pageId].description)
link(rel="stylesheet" href="css/style.css")
body
include common/_header.pug
h1 トップページ
main
p トップページテキスト
include common/_footer.pug
- 「- var pageId = "index"」:ページ判定。
- 「#{pages[pageId].title}」:タイトル変数。
- 「pages[pageId].description」:ディスクリプション変数。
上記の変数タグを埋め込んだ後、gulp pugコマンドを入力して、index.htmlの中身を見ると下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<meta name="description" content="トップページディスクリプション">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>ヘッダー</header>
<h1>トップページ</h1>
<main>
<p>トップページテキスト</p>
</main>
<footer>フッター</footer>
</body>
</html>
jsonで記述したタイトルとディスクリプションが出力されていることがわかります。
ニュース用のタイトルやディスクリプションを埋め込む場合は下記のようになります。
- var pageId = "news-index"
doctype html
html(lang="ja")
head
meta(charset="utf-8")
title #{pages[pageId].title}
meta(name='description' content=pages[pageId].description)
link(rel="stylesheet" href="css/style.css")
body
include ../common/_header.pug
h1 ニュースページ
main
p ニュースページテキスト
include ../common/_footer.pug
pageIdがニュース用のものになり、タイトルとディスクリプションの変数は変わりません。出力した「news/index.html」の中身は下記のようになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ニュースページタイトル</title>
<meta name="description" content="ニュースディスクリプション">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>ヘッダー</header>
<h1>ニュースページ</h1>
<main>
<p>ニュースページテキスト</p>
</main>
<footer>フッター</footer>
</body>
</html>
インクルードファイル内で相対パスを取得する
ヘッダーやフッターなどをインクルードしている場合、インクルード内で記述しているa要素などのパスを取得したいと思います。方法としてはいろいろありますが、ここでは「pug」ファイルにパスを記述し、変数に渡して相対パスを取得します。
- var relativePath = "./"
「index.pug」に上記の記述をします。「news/index.pug」であれば下記のようになります。
- var relativePath = "../"
インクルードファイルの「_header.pug」には下記のように記述します。
header ヘッダー
a(href=`${relativePath}`) トップページ
上記の上記の「href」内の「`${relativePath}`」でパスが返ります。記述後にgulp pugを入力して出力します。「index.html」と「news/index.html」の「トップページ」のパスは下記のようになります。
<header>ヘッダー
<a href="./">トップページ</a>
</header>
上記、「index.html」の「トップページ」のパスは「./」、「news/index.html」から見た場合は下記のように「../」となります。
<header>ヘッダー
<a href="../">トップページ</a>
</header>
今回の方法は画像やCSSのパスにも利用できます。
img(src=`${relativePath}images/hoge.jpg` width="100" height="100" alt="画像")
記述がわかりづらい要素での記法
picture要素
picture
source(media="(max-width:400px)" srcset=`${relativePath}images/sp.jpg 400w` sizes="100vw")
source(media="(max-width:600px)" srcset=`${relativePath}images/tab.jpg 600w` sizes="100vw")
img(src=`${relativePath}images/pc.jpg` alt="代替")
figureにネストしているpicture要素
figure
picture
source(media="(max-width:400px)" srcset=`${relativePath}images/sp.jpg 400w` sizes="100vw")
source(media="(max-width:600px)" srcset=`${relativePath}images/tab.jpg 600w` sizes="100vw")
img(src=`${relativePath}images/pc.jpg` alt="代替")
figcaption 画像キャプション
まとめ
- Pugは静的なテンプレートエンジン。
- Pugは専用の記法がある。
- gulp-pugはGulp用のPug。
- Pugは基本的にJavaScriptと同様のことができる。
Pugで記述するhtmlは独特の記法ですが、タグで囲う必要がないので楽なのと、一ファイルに記述するコード量を抑えることができます。


コメント