GulpでテンプレートエンジンのEJSを使ってみた

技術情報

EJS – JavaScript Templates

最近、静的なテンプレートを生成する方法としていろいろ試行錯誤していたのですが、JavaScriptで静的なhtmlを生成できるEJSというものを知り、使ってみることにしました。

EJSとは

EJS(Embedded JavaScript)は「.ejs」という拡張子のファイル内にあるhtmlにJavaScriptを埋め込む形で使用します。EJSを利用するには「Node.js」が必要になります。EJSにはGulp用のEJSがあり、Gulpで使うことができます。

EJSで何ができるか

ざっくりとですが、EJSは下記のようなことができます。

  • ループや条件分岐。
  • 共通ファイルの読み込み(インクルード)やパラメータの引き渡し。
  • JavaScriptと同様に、数、文字列、配列、オブジェクトなどを扱える。
  • htmlファイルへの出力。

gulp-ejsを導入する

EJSを利用するには「Node.js」が必要なので前もってインストールしておきます。「Node.js」の導入は「Node.jsを導入する」を参照してください。

gulp-ejsをインストールする

今回、EJSはGulpで利用するので、下記のコマンドを入力してgulp-ejsをインストールします。

npm i -D gulp-ejs

gulpfile.jsに下記の記述をし、EJSを利用できるようにします。

var ejs = require("gulp-ejs");

拡張子をhtmlにする

EJSから出力する際の拡張子をhtmlにするために下記の記述をします。

npm i -D gulp-rename

インストールしたgulp-renameを利用できるようにgulpfile.jsに下記の記述をします。

var rename = require("gulp-rename");

gulp-renameはファイルを出力する際に拡張子をリネームできるプラグインです。

gulpfile.jsにgulp-ejsのタスクを記述する

次にgulpfile.jsにgulp-ejsのタスクを記述します。

//EJS(テンプレートエンジン)
gulp.task("ejs", function() {
    gulp.src(
       ["src/ejs/**/*.ejs",'!' + "src/ejs/**/_*.ejs"] //参照するディレクトリ、出力を除外するファイル
    )
    .pipe(ejs())
    .pipe(rename({extname: ".html"})) //拡張子をhtmlに
    .pipe(gulp.dest("dest/")) //出力先
});
  • 「”src/ejs/**/*.ejs”」はサブディレクトリも含めた「.ejs」ファイルを参照。
  • 「’!’ + “src/ejs/**/_*.ejs”」はサブディレクトリも含めた「_」が先頭についた「.ejs」ファイルの出力(インクルードファイル)を除外。
  • 「.pipe(rename({extname: “.html”}))」は通常「.ejs」で出力される拡張子を「.html」にリネーム。
  • 「.pipe(gulp.dest(“dest/”))」で「dest」というディレクトリ以下にファイルを出力。

EJSを使う

EJSファイルを作成する

作業するディレクトリに手動でEJSファイルを作成します。今回は「src/ejs/」にindex.ejsを作成しました。index.ejsには何かしらのhtmlを記述しておきます。

EJS 「src/ejs/」にindex.ejsを作成
「src/ejs/」に「index.ejs」を作成

htmlとして出力する

次に「gulpfile.js」がある階層で下記のコマンドを入力してhtmlを出力します。

gulp ejs

すると、gulpfile.jsに記述した「.pipe(gulp.dest(“dest/”))」が動作し、「dest/」直下にindex.htmlが出力されます。

EJS 「dest/」直下にindex.html
「dest/」直下に「index.html」

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

EJS ディレクトリ階層がコピーされる
ディレクトリ階層がコピーされる

共通ファイルをインクルードする

ヘッダーやフッターなどの共通部分をinclude文を利用して、複数のページで共通で使用することができます。

_header.ejs(ヘッダー)

今回は「/src/ejs/common/」に「_header.ejs」として共通で使うヘッダーを作成しました。

EJS 「/src/ejs/common/」に「_header.ejs」
「/src/ejs/common/」に「_header.ejs」

ヘッダーの内容は下記のようにしました。

<header>
    ヘッダー
</header>

_footer.ejs(フッター)

今回は「/src/ejs/common/」に「_footer.ejs」として共通で使うフッターを作成しました。

EJS 「/src/ejs/common/」に「_footer.ejs」
「/src/ejs/common/」に「_footer.ejs」

フッターの内容は下記のようにしました。

<footer>
    フッター
</footer>

index.ejsにヘッダーとフッターをインクルードする

index.ejsに下記のように記述します。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>トップタイトル</title>
</head>
<body>
    <div class="conatiner">

        <% include common/_header %>

        <p>
            トップ
        </p>

        <% include common/_footer %>

    </div>
</body>
</html>
  • 「<% include common/_header %>」でヘッダーをインクルード。
  • 「<% include common/_footer %>」でフッターをインクルード。

上記のインクルードを行った後、gulp ejsコマンドを入力して、index.htmlの中身を見ると下記のようになります。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>トップタイトル</title>
</head>
<body>
    <div class="conatiner">

        <header>
            ヘッダー
        </header>

        <p>
            トップ
        </p>

        <footer>
            フッター
        </footer>

    </div>
</body>
</html>

index.ejsにインクルードしたヘッダーとフッターがindex.htmlに出力されています。

「src/ejs/news/index.ejs」に上記のインクルードを行う場合は、階層が一つ変わるので下記のように「../common/」となります。

  • 「<% include ../common/_header %>」
  • 「<% include ../common/_footer %>」

ifやforなど

EJSはifやforで判定や繰り返しなどを行うことができます。

if文

<% if (data.type === 'red') { %>
<div class="red">赤</div>
<% } else if (data.type === 'green') { %>
<div class="green">緑</div>
<% } else { %}
<div class="blue">上記以外(青)</div>
<% } %>

for文

<ul>
<% for (var i = 0; i < 5; i++) { %>
<li><%= i+1 %>個目のli。</li>
<% } %>
</ul>
EJS for文出力
for文出力

jsonでタイトルやディスクリプションを出力する

jsonファイル

EJSはjsonを利用してtitleやdiscriptionの内容を出力させることができます。まずは下記のような内容でjsonを作成します。

{
    "pages":[
        {
            "title": "トップページタイトル",
            "description": "トップページディスクリプション"
        },
        {
            "title": "ニュースページタイトル",
            "description": "ニュースページディスクリプション"
        }
    ]
}

jsonファイルは「pages.json」として下記の階層に設置しました。

EJS 「pages.json」を設置
「pages.json」を設置

gulpfile.jsにjsonの記述を追記

jsonをパースできるように下記の記述をgulpfile.jsに追記します。

var fs = require("fs");

次にgulpfile.jsのejsのタスクに「var json = JSON.parse(fs.readFileSync(“./pages.json”));」と「.pipe(ejs())」内に「json」を追記します。

//EJS(テンプレートエンジン)
gulp.task("ejs", function() {
    var json = JSON.parse(fs.readFileSync("./pages.json")); //追記
    gulp.src(
       ["src/ejs/**/*.ejs",'!' + "src/ejs/**/_*.ejs"] //参照するディレクトリ、出力を除外するファイル
    )
    .pipe(ejs(json)) //jsonを追記
    .pipe(rename({extname: ".html"})) //拡張子をhtmlに
    .pipe(gulp.dest("dest/")) //出力先
});

index.ejsにタイトルとディスクリプションの変数タグを埋め込む

index.ejsのtitleとdescription要素に変数タグを埋め込みます。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title><%= pages[0].title %></title>
<meta name="description" content="<%= pages[0].description %>">
</head>
<body>
    <div class="conatiner">

        <% include common/_header %>

        <p>
            トップ
        </p>

        <ul>
        <% for (var i = 0; i < 5; i++) { %>
        <li><%= i+1 %>個目のli。</li>
        <% } %>
        </ul>

        <% include common/_footer %>

    </div>
</body>
</html>
  • 「<%= pages[0].title %>」:トップページ用タイトル変数タグ
  • 「<%= pages[0].description %>」:トップページ用ディスクリプション変数タグ

上記の変数タグを埋め込んだ後、gulp ejsコマンドを入力して、index.htmlの中身を見ると下記のようになります。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>トップページタイトル</title>
<meta name="description" content="トップページディスクリプション">
</head>
<body>
    <div class="conatiner">

        <header>
    	    ヘッダー
        </header>

        <p>
            トップ
        </p>

        <ul>
        <li>1個目のli。</li>
        <li>2個目のli。</li>
        <li>3個目のli。</li>
        <li>4個目のli。</li>
        <li>5個目のli。</li>
        </ul>

        <footer>
    	    フッター
        </footer>

    </div>
</body>
</html>

jsonで記述したタイトルとディスクリプションが出力されていることがわかります。

pages.jsonは配列となっているので、上から順に「[0]」、「[1]」となります。ニュース用のタイトルやディスクリプションを埋め込む場合は下記のようになります。

  • 「<%= pages[1].title %>」:ニュースページ用タイトル変数タグ
  • 「<%= pages[1].description %>」:ニュースページ用ディスクリプション変数タグ

インクルードファイル内で相対パスを取得する

ヘッダーやフッターなどをインクルードしている場合、インクルード内で記述しているa要素などのパスを取得したいと思います。方法としてはいろいろありますが、ここではインクルード文にパス記述し、相対パスを取得します。

<% include common/_header %>

上記のインクルード文を下記に変更します。

<%- include('common/_header', {rel_path:'./'}) %>

「<%-」の「-」はエスケープを回避するために記述しています。「rel_path:’./’」でindex.ejs(index.html)のパスを渡しています。「news/index.ejs」の場合は下記のようになります。

<%- include('../common/_header', {rel_path:'../'}) %>

インクルードファイルの「_header.ejs」には下記のように記述します。

<header>
    <a href="<%= rel_path %>">トップページ</a>
</header>

上記の「href」内の「<%= rel_path %>」でパスが返ります。記述後にgulp ejsを入力して出力します。「index.html」と「news/index.html」の「トップページ」のパスは下記のようになります。

<header>
    <a href="./">トップページ</a>
</header>

上記、「index.html」の「トップページ」のパスは「./」、「news/index.html」から見た場合は下記のように「../」となります。

<header>
    <a href="../">トップページ</a>
</header>

今回の方法は画像やCSSのパスにも利用できます。

まとめ

  • EJSは静的なテンプレートエンジン。
  • gulp-ejsはGulp用のEJS。
  • EJSは基本的にJavaScriptと同様のことができる。

gulp-ejsのhtmlは基本的にはいつも通りなので、それほど学習コストが高くなく、JavaScriptができる方ならスムーズに入れると思います。Gulpを利用している方であれば、おすすめのテンプレートエンジンです。

今回は手動でindex.ejsなどを作成しましたが、jsonを利用して自動でhtmlファイルを出力する方法もあるようなので、おいおい試していきたいと思います。

スポンサーリンク
技術情報
スポンサーリンク
シェアする
ボヘミアンをフォローする
この記事が気に入ったら
いいね!しよう
最新情報をお届けします。
スポンサーリンク

コメント