EJS+gulpで静的サイトのHTML生成


静的なHTMLをそこそこ制作する案件があったので
EJSを試しに使ってみました。
複数ページの情報をJSONで管理し、
テンプレートエンジン“EJS”でHTMLを書き出してみます。

こちらのページを参考にさせていただきました。
[Gulp＋EJS＋JSONからHTMLファイルを生成する](http://kinacom.hatenablog.jp/entry/2015/08/04/211403)


▼環境

```
 "node"   : "v4.1.1",
 "npm"    : "2.14.4",
```

##カンタンなEJS機能紹介

▼インクルード

```
<% include hoge %>
```
hogeファイルをインクルードで読み込む。

▼<% %>内でJavaScriptを記述できます。（公式より）

```
<% if (user) { %>
  <h2><%= user.name %></h2>
<% } %>
```

[こちらの記事](http://qiita.com/hisahayashi/items/2211adc1995709faaa14)も参考になりました。


##準備編

npmでgulp-ejsをインストールします。

```
npm install --save-dev gulp-ejs
```

cf.[EJS](http://ejs.co/),[npm gulp-ejs](https://www.npmjs.com/package/gulp-ejs)


gulpの設定はこちらです。
補足ですがconfigファイルでpathの情報などは別ファイルで保存しています。

後述のtemplate.ejsに
pages.jsonのデータを流しこんでいきます。
"pages"の数だけHTMLを生成する設定です。

```gulp/ejs.js
'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 ));
  }
});

```

##テンプレート編

```template.ejs
<!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.json
{
  "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ファイルはこんな感じです。

```_head.ejs
<% 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タグに設定しています。


```_header.ejs
<%
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では

```_header.ejs
<% ( data.id == "index000" ) ? Class = 'current' : Class = '' -%>
```
HTMLのファイル名と"id"が同じ時に
currentクラスを付加しています。


```_contents.ejs
<% 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してみましょう！

```console.log
gulp ejs
```

こちらのようなHTMLが生成されるとおもいます。

```HTML:page000.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さんの記事](http://liginc.co.jp/web/html-css/html/144170)に倣っているためです。

ただejs.jsの記述の通り
pages.jsonに記載されているページのみ生成されますので
本コードには必須ではありません。



##まとめ
一度に複数のHTMLを生成できるのは
効率的で気持ちいいですね！

実際の運用にはまだ最適化が必要そうですが
静的サイトのテンプレート展開などに使えるのではないでしょうか。






##参考リンク
[Gulp＋EJS＋JSONからHTMLファイルを生成する](http://kinacom.hatenablog.jp/entry/2015/08/04/211403)
[EJSの使い方を訳してみた（中途半端でごめんなさい）](http://qiita.com/hisahayashi/items/2211adc1995709faaa14)
[テンプレートエンジン「EJS」とタスクランナー「Gulp.js」で爆速HTMLコーディング](http://liginc.co.jp/web/html-css/html/144170)