静的なHTMLをそこそこ制作する案件があったので
EJSを試しに使ってみました。
複数ページの情報をJSONで管理し、
テンプレートエンジン“EJS”でHTMLを書き出してみます。
こちらのページを参考にさせていただきました。
Gulp+EJS+JSONからHTMLファイルを生成する
▼環境
"node" : "v4.1.1",
"npm" : "2.14.4",
##カンタンなEJS機能紹介
▼インクルード
<% include hoge %>
hogeファイルをインクルードで読み込む。
▼<% %>内でJavaScriptを記述できます。(公式より)
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
こちらの記事も参考になりました。
##準備編
npmでgulp-ejsをインストールします。
npm install --save-dev gulp-ejs
cf.EJS,npm gulp-ejs
gulpの設定はこちらです。
補足ですがconfigファイルでpathの情報などは別ファイルで保存しています。
後述のtemplate.ejsに
pages.jsonのデータを流しこんでいきます。
"pages"の数だけHTMLを生成する設定です。
'use strict';
const gulp = require( 'gulp' );
const fs = require( 'fs' );
const plumber = require( 'gulp-plumber' );
const rename = require( 'gulp-rename' );
const ejs = require( 'gulp-ejs' );
const config = require( '../config' );
const jsonData = 'path/to/pages.json';
const template = 'path/to//template.ejs';
const json = JSON.parse(fs.readFileSync( jsonData ));
const pages = json.pages;
gulp.task( 'ejs', () => {
for (let i = 0; i < pages.length; i++) {
const id = pages[i].id;
gulp.src( template )
.pipe( plumber() )
.pipe(ejs({
jsonData: pages[i]
}))
.pipe( rename(id + ".html") )
.pipe(gulp.dest( config.ejs.dest ));
}
});
##テンプレート編
<!DOCTYPE html>
<html lang="ja">
<% include common/_head %>
<body>
<section id="all">
<% include common/_header %>
<% include common/_contents %>
</section>
<script src="script.js"></script>
</body>
</html>
template.ejsと同階層にcommonフォルダを設置し、
includeファイルを置いています。
どうもWordPressのテンプレートのような形式
(ex. header.phpに分けた時にタグが途中できれる)
がしっくりこないので、ブロックごとにincludeしていきました。
▼データ元となるpages.jsonはこちらです(html:1ファイル分)
{
"pages": [
{
"id": "page000",
"title": "タイトル",
"contents": [
{
"id": "child000",
"h2": "タイトルその1",
"tag": [
"タグ1",
"タグ2",
"タグ3",
"タグ4"
],
"summary": "サマリーサマリーサマリーサマリーサマリーサマリー",
"reference": {
"text": "リファレンス",
"url" : "http://qiita.com/"
},
"exercises": "テキスト"
},
{
"id": "child001",
"h2": "タイトルその2",
"tag": [
"タグ1",
"タグ2",
"タグ3",
"タグ4"
],
"summary": "サマリーサマリーサマリーサマリーサマリーサマリー",
"reference": {
"text": "リファレンス",
"url" : "http://qiita.com/"
},
"exercises": "テキスト"
}
]
}
]
}
▼各includeファイルはこんな感じです。
<% var data = jsonData; %>
<head>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<title><%= data.title %></title>
<link rel="stylesheet" href="files/css/style.css">
</head>
↑gulp/ejs.jsでtemplate.ejsに渡した
jsonのvalueをtitleタグに設定しています。
<%
var data = jsonData;
var Class = '';
%>
<header id="header">
<nav class="wrap">
<ul id="navi">
<% ( data.id == "page000" ) ? Class = 'current' : Class = '' -%>
<li>
<a href="page000.html" class="<%= Class -%>" >menu000</a>
</li>
<% ( data.id == "page001" ) ? Class = 'current' : Class = '' -%>
<li>
<a href="page001.html" class="<%= Class -%>" >menu001</a>
</li>
<% ( data.id == "page002" ) ? Class = 'current' : Class = '' -%>
<li>
<a href="page002" class="<%= Class -%>" >menu002</a>
<li>
</ul>
</nav>
</header>
_header.ejsでは
<% ( data.id == "index000" ) ? Class = 'current' : Class = '' -%>
HTMLのファイル名と"id"が同じ時に
currentクラスを付加しています。
<% var data = jsonData; %>
<section id="main">
<div class="wrap">
<h1><%= data.title %></h1>
//▼contentsをループで生成
<% for( var i = 0; i < data.contents.length; i++ ) { -%>
<section id="<%= data.contents[i].id %>" class="content">
<h2><%= data.contents[i].h2 %></h2>
<div class="content-ttl">
<ul class="tag">
//▼tagリストをループ生成
<% for( var j = 0; j < data.contents[i].tag.length; j++ ) { -%>
<li><%= data.contents[i].tag[j] %></li>
<% } %>
</ul>
</div>
<div class="content-box">
<p class="summary"><%= data.contents[i].summary %></p>
<p class="reference">
<a href="<%= data.contents[i].reference.url -%>">
<%= data.contents[i].reference.text %>
</a>
</p>
</div>
<div class="btn"><a href="#"><%= data.contents[i].exercises %></a></div>
</section>
<% } %>
</div>
</section>
以上で準備が整いましたので
gulpでbuildしてみましょう!
gulp ejs
こちらのようなHTMLが生成されるとおもいます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="description" content="">
<meta name="keywords" content="">
<meta name="viewport" content="width=device-width">
<title>タイトル</title>
<link rel="stylesheet" href="files/css/style.css">
</head>
<body>
<section id="all">
<header id="header">
<nav class="wrap">
<ul id="navi">
<li>
<a href="page000.html" class="current" >menu000</a>
</li>
<li>
<a href="page001.html" class="" >menu001</a>
</li>
<li>
<a href="page002" class="" >menu002</a>
<li>
</ul>
</nav>
</header>
<section id="main">
<div class="wrap">
<h1>タイトル</h1>
<section id="child000" class="content">
<h2>タイトルその1</h2>
<div class="content-ttl">
<ul class="tag">
<li>タグ1</li>
<li>タグ2</li>
<li>タグ3</li>
<li>タグ4</li>
</ul>
</div>
<div class="content-box">
<p class="summary">サマリーサマリーサマリーサマリーサマリーサマリー</p>
<p class="reference">
<a href="http://qiita.com/">リファレンス</a>
</p>
</div>
<div class="btn"><a href="#">テキスト</a></div>
</section>
<section id="child001" class="content">
<h2>タイトルその2</h2>
<div class="content-ttl">
<ul class="tag">
<li>タグ1</li>
<li>タグ2</li>
<li>タグ3</li>
<li>タグ4</li>
</ul>
</div>
<div class="content-box">
<p class="summary">サマリーサマリーサマリーサマリーサマリーサマリー</p>
<p class="reference">
<a href="http://qiita.com/">リファレンス</a>
</p>
</div>
<div class="btn"><a href="#">テキスト</a></div>
</section>
</div>
</section>
</section>
<script src="script.js"></script>
</body>
</html>
※現状ですとincludeした箇所のインデントが少しずれてしまうので調整が必要です。
(掲載HTMLコードは多少整えてあります)
また、include接頭辞にアンダーバーを付けているのは
LIGさんの記事に倣っているためです。
ただejs.jsの記述の通り
pages.jsonに記載されているページのみ生成されますので
本コードには必須ではありません。
##まとめ
一度に複数のHTMLを生成できるのは
効率的で気持ちいいですね!
実際の運用にはまだ最適化が必要そうですが
静的サイトのテンプレート展開などに使えるのではないでしょうか。
##参考リンク
Gulp+EJS+JSONからHTMLファイルを生成する
EJSの使い方を訳してみた(中途半端でごめんなさい)
テンプレートエンジン「EJS」とタスクランナー「Gulp.js」で爆速HTMLコーディング