最近、静的なテンプレートを生成する方法としていろいろ試行錯誤していたのですが、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を記述しておきます。
htmlとして出力する
次に「gulpfile.js」がある階層で下記のコマンドを入力してhtmlを出力します。
gulp ejs
すると、gulpfile.jsに記述した「.pipe(gulp.dest(“dest/”))」が動作し、「dest/」直下にindex.htmlが出力されます。
gulpやejsのバージョンにもよりますが、「base」プロパティを指定せずとも「src/ejs/news/」にindex.ejsと作成した場合、階層はそのままコピーされ、「dest/」に「news/index.ejs」が出力されます。ディレクトリ階層がそのままコピーされない場合は、「base」プロパティを使用しましょう。
共通ファイルをインクルードする
ヘッダーやフッターなどの共通部分をinclude文を利用して、複数のページで共通で使用することができます。
_header.ejs(ヘッダー)
今回は「/src/ejs/common/」に「_header.ejs」として共通で使うヘッダーを作成しました。
ヘッダーの内容は下記のようにしました。
<header> ヘッダー </header>
_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>
jsonでタイトルやディスクリプションを出力する
jsonファイル
EJSはjsonを利用してtitleやdiscriptionの内容を出力させることができます。まずは下記のような内容でjsonを作成します。
{ "pages":[ { "title": "トップページタイトル", "description": "トップページディスクリプション" }, { "title": "ニュースページタイトル", "description": "ニュースページディスクリプション" } ] }
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ファイルを出力する方法もあるようなので、おいおい試していきたいと思います。
コメント