前書き
本記事のゴール
この記事では、EJS テンプレートを利用することで、HTMLのコーディングの効率を向上させる方法を理解することを目指します。
この記事で解説する内容
- EJSの概要について説明します
- EJSをプロジェクトに導入する方法について説明します
- EJSを利用した簡単な実例を紹介します
この記事で解説しない内容
- EJSの詳細な文法については説明しません
- EJSテンプレートで外部JSONデータを活用する方法については説明しません
[参考] EJSの文法に関する詳細説明
シリーズ記事
この記事はシリーズ 「ちょっとがんばるWebサイト開発 on Webpack5」 の記事です。
シリーズ全体の概要は 以下のリンク先記事 にまとめられています。
この記事では Webpack5 (version5.X.X) を対象としています。
背景知識
EJSとは何か
EJS (Embedding JavaScript template) は、HTMLファイルを生成するテンプレートを記述するための言語仕様です。HTML形式をベースに記述されており、そこにJavaScriptの構文を挿入することができます。JavaScriptの構文が利用できるため、条件分岐やループ等を用いてHTML要素の宣言をコントロールすることができます。
EJSファイルは、HTMLファイルを生成するための「テンプレート」として利用します。EJSファイルそれ自体はWebサーバにアップロードせず、コンパイルした結果得られるHTMLファイルを公開するという形で利用します。
この記事ではWebpackを利用してプロジェクトにEJSを導入するところに焦点を当てるため、EJSの詳細には立ち入りません。
[参考] EJS関連記事
EJSを使うと何が良いのか
HTML形式には文書構造を宣言するための限られた構文しか用意されていないため、生のHTMLファイルを記述する際に不都合が生じることは多いと思います。
例えば、GitHubユーザのレポジトリ一覧 に見られるように、ほとんど同一の構造を持つHTML要素を多数並べたいという状況が考えられます。1 こうした状況において、各種プログラミング言語で実装されている「ループ(JavaScriptにおけるfor文)」の機能を活用して記述できるとすれば、より効率的で保守性の高いコーディングができるでしょう。
生のHTML/CSS/JavaScript2 のみで静的Webサイトを開発した経験がある人ならば誰しも一度は「HTMLのコーディングでもプログラミング言語のような記述をしたい」と考えたことがあると思いますが、EJSはそれを実現する1つのアプローチとなっています。
EJSを使う必要があるのか
EJS以外の技術でEJS同様の処理を実行することについて考えてみます。
1つ目は既存のHTMLテンプレートエンジンを利用する方法です。
EJS同様に広く利用されているHTMLテンプレートエンジンとしては Pug というものがあるようです。JavaScriptテンプレートエンジンのPug(Jade)とEJSの比較 - Qiita 等の記事で確認できるように、EJSとPugの記法は大きく異なるため、自分の好みに合わせてテンプレートエンジンを選ぶと良いでしょう。
[参考] Pug関連記事
2つ目はプロジェクトに特化したHTMLテンプレートエンジンを自作する方法です。
EJSのコンパイラがやっていることは「部分的にJavaScriptコードが挿入されたHTMLファイルをEJSの言語仕様に則って生のHTMLファイルに変換する」という作業です。ということは、適当な言語仕様とコンパイラさえ用意することさえできれば、EJS同様の処理を実行することは難しくありません。「言語仕様(ルール)」「コンパイラ(変換器)」といっても、自身のプロジェクトで必要な最低限のルールと任意のプログラミング言語で実装された変換器が用意できれば十分でしょう。
この意味で、「EJSを導入するほど複雑な処理を行わない」「EJSでは実現できない特殊な処理を行いたい」という場合には自分で実装するというのも1つの選択肢になるかと思います。
3つ目はHTMLテンプレートエンジン以外の技術を利用する方法です。
最近では Vue, React, Angular 等のJavaScriptフロントエンドフレームワークを用いる場合が増えてきているようです。これらのフレームワークは通常HTML要素を 動的に 生成するため、HTMLファイルを 静的に 生成するEJSの技術とは一線を画す存在となっています。3 これらの技術の差異について理解しておくと後々役に立つような気がします。
「HTML要素/ページを 静的に 生成する」とは、ローカル環境においてEJS等のソースファイルをコンパイルすることで事前にHTML要素/ファイルを生成しておくことを指しています。一方で「HTML要素/ページを 動的に 生成する」とは、Webページがアクセスされた際にサーバにおいてHTML要素/ファイルを生成することを指しています。どちらのアプローチをとるべきかは、Webサイトの特性等を考慮して決定します。
[参考] JavaScriptフロントエンドフレームワーク
方法
サンプルコードをGitHubで公開しています。記事と併せてご覧ください。
/website/website-dev-on-webpack5/ejs-on-webpack5
実装例の説明では、ファイル/フォルダパスを ルート相対パス の形式で記述しています。ここでルートはプロジェクトルートまたはWebサイトのドキュメントルートに相当します。
準備
WebpackおよびEJS等のnpmパッケージの利用には Node.js が必要です。
インストールが未実施の場合には、以下のリンクからインストールしておいてください。
また、動作確認を行うための Node.js プロジェクトを作成しておきます。
適当な名前のディレクトリ(ここでは my-ejs-project
)を用意した上で、そのディレクトリにおいて npm init
コマンドを実行することで Node.js プロジェクトを新規作成することができます。
# my-ejs-projectディレクトリの作成
$ mkdir /path/to/my-ejs-project
$ cd /path/to/my-ejs-project
# Node.jsプロジェクトの作成
$ npm init
npm init
コマンドを実行するとプロジェクトに関する情報を入力するよう促されますが、今回は適当な設定にしておいて問題ありません。今後必要に応じて適宜変更しましょう。
コマンド実行完了後、 /package.json
という設定ファイルが新規作成されていることを確認したら事前準備完了です。
手順概要
-
npmパッケージを導入する
EJSからHTMLを生成するのに必要なnpmパッケージwebpack
webpack-cli
html-webpack-plugin
html-loader
template-ejs-plugin
をプロジェクトに追加します。 -
Webpackの設定ファイルを記述する
EJSからHTMLを生成する手順やルールを設定ファイル/webpack.config.js
に記述します。 -
EJSファイルを作成する
HTMLファイルのテンプレートとなるEJSファイル/src/source.ejs
を作成します。 -
EJSファイルをコンパイルしてHTMLファイルを生成する
Webpackを実行することでEJSファイルのコンパイルを実行し、HTMLファイル/dist/target.html
を生成します。
[手順1] npmパッケージを導入する
今回は Webpack を利用してEJSファイルのコンパイルを行います。
まず初めに、Webpackを利用するのに必要な webpack
webpack-cli
パッケージをインストールします。
Webpack5(version5.X.X)をインストールするため、バージョン指定を行っています。
npm install --save-dev webpack@5 webpack-cli@5
次に、EJSファイルをコンパイルするのに必要な html-webpack-plugin
html-loader
template-ejs-loader
パッケージをインストールします。
npm install --save-dev html-webpack-plugin html-loader template-ejs-loader
[手順2] Webpackの設定ファイルを記述する
Webpackは、適切に設定を記述することで様々な処理を実行することができます。
ここではEJSファイル /src/source.ejs
をコンパイルして /dist/target.html
を生成するための必要最小限の設定を示します。
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = function() {
return {
mode: "development",
entry: {},
output: {
/**
* OUTPUT_DIRECTORY = /dist
*/
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: /\.ejs$/,
use: [
/**
* HtmlLoader -> TemplateEjsLoader
*/
"html-loader",
"template-ejs-loader",
],
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "source.ejs"),
filename: "target.html",
minify: {
collapseWhitespace: true,
preserveLineBreaks: true,
},
}),
],
}
}
上記のWebpack設定には同シリーズ別記事 「ちょっとがんばるWebサイト開発 on Webpack5 - HTMLをコピー&ペーストする」 と共通する部分が多数あります。共通部分に関する説明として、同シリーズ別記事の説明を一部改変して引用したものを載せておきます。
上記の設定を要約すると、
Webpackのプラグイン設定箇所に、適切な設定を含むHtmlWebpackPlugin({...})
オブジェクトを追加する
となります。特に注目すべきパラメータは以下の通りです。
template: path.resolve(__dirname, "src", "source.html")
入力HTMLファイルの 絶対パス を指定する
filename: "target.html"
出力HTMLファイルの 相対パス を指定する
注目すべき最も大きな相違点はWebpackのルール設定です。
Webpackは、ルール設定で指定された内容に従って最適化/変換処理等を行います。
{ test: /\.ejs$/ }
および { use: [ "html-loader", "template-ejs-loader" ] }
という設定を記述することで、拡張子 *.ejs
のファイルに対して ejs-template-loader
の変換処理と html-loader
の変換処理をこの順で適用することができます。
大雑把に言えば、 template-ejs-loader
はEJSテンプレートをコンパイルしてHTMLページを生成するもので、 html-loader
は template-ejs-loader
等の出力結果をWebpackのビルドプロセスで取り扱えるようにするものです(この記事では詳細を割愛します)。
HtmlWebpackPluginプラグインでは、デフォルトでEJSローダーが適用されることになっているため、より簡潔な記述でもEJSテンプレートファイルを取り扱うことができます。例えば、 webpack.config.js
を以下のように記述することができます(折りたたみ要素の中にあります)。
/webpack.config.js の設定内容例
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = function() {
return {
mode: "development",
entry: {},
output: {
path: path.resolve(__dirname, "dist"),
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "source.ejs"),
filename: "target.html",
minify: {
collapseWhitespace: true,
preserveLineBreaks: true,
},
}),
],
}
}
例において webpack
webpack-cli
html-webpack-plugin
プラグインは必要ですが、 html-loader
template-ejs-loader
プラグインは不必要であるため、インストールの手間を削減することができます。
ただし、 デフォルトのEJSローダーはEJSの構文すべてをサポートしているわけではないことに注意してください 。EJSの構文すべてを扱うためには、追加プラグイン html-loader
ejs-template-plugin
の導入および追加設定を行います。詳細はHtmlWebpackPluginの公式ドキュメントに詳しいです。
[参考]
[参考] Webpack設定
[参考] html-webpack-plugin / html-loader / template-ejs-loader
[手順3] EJSファイルを作成する
手順2の設定に従ってEJSファイルを作成します。
上記設定ファイル /webpack.config.js
では入力EJSファイルパスを /src/source.ejs
に指定したので、その位置に source.ejs
ファイルを作成しましょう。
ファイル内容はどんなものでも構いませんが、ここでは例として以下のように記述することにします(折りたたみ要素の中にあります)。
/src/source.ejs の入力内容例
<!doctype html>
<html>
<head>
<title>My EJS Project</title>
</head>
<body>
<h1>Hello, Webpack!</h1>
<ul>
<% let plugins = [ "html-webpack-plugin", "html-loader", "template-ejs-loader" ]; %>
<% for (let idx = 0; idx < plugins.length; idx++) { %>
<li><p>Hello, <%= plugins[idx] %>!</p></li>
<% } %>
</ul>
</body>
</html>
[手順4] EJSファイルをコンパイルしてHTMLファイルを生成する
手順1〜3でEJS→HTML変換のための準備が完了しました!
それではWebpackを用いて /src/source.ejs
から /dist/target.html
を生成してみましょう。
ターミナルで npx webpack
コマンドを実行することでビルド作業が開始します。
# ディレクトリ移動
cd /path/to/my-ejs-project
# Webpackコマンド実行
npx webpack
ビルドが正常に完了すれば、HTMLファイル /dist/target.html
が生成されていることを確認できると思います。ファイルの内容を確認すると、EJSで記述された部分が展開されてHTMLになっているはずです(折りたたみ要素の中にあります)。
/dist/target.html の出力内容例
<!doctype html>
<html>
<head>
<title>My EJS Project</title>
</head>
<body>
<h1>Hello, Webpack!</h1>
<ul>
<li><p>Hello, html-webpack-plugin!</p></li>
<li><p>Hello, html-loader!</p></li>
<li><p>Hello, template-ejs-loader!</p></li>
</ul>
</body>
</html>
上記手順では、Webpackを利用してEJSをコンパイルする方法を示しましたが、Webpackを利用しないで実現する方法もあります。
EJS公式サイト にも書かれているように、npmパッケージ ejs
を導入した上で npx ejs
コマンドを実行することで所望の結果を得ることができます。
# EJSの導入
npm install --save-dev ejs
# EJSの実行
npx ejs src/source.ejs -o dist/target.html
EJSを単体で利用したい場合にはこの方法でも十分ですが、その他にも様々な処理を一挙に行いたい場合にはWebpackを利用すると便利です。一方で、様々な処理が可能なWebpackはその分だけ学習コストが高いという側面もあります。プロジェクトの開発環境やコスト等を考慮しながら導入を検討すると良いと思います。
後書き
サンプルコード
/website/website-dev-on-webpack5/ejs-on-webpack5
-
実際には、GitHubのWebサイトでは各ページのコンテンツが動的に生成されていると思いますが、ここではそういったコンテンツが事前に用意できるような場合を考えていると思ってください。 ↩
-
一般に「生の」というフレーズは「無加工の」「比較的低レベルの」というような意味で使用されますが、ここでは「Webサイトに直接アップロードするそのままの」というような意味も含んでいます。実装するソースファイルの内容は必ずしもWebサイトにアップロードして公開するHTML/CSS/JavaScriptファイルと同一でなくても良いので、実装の際にはより便利な記法やプログラミング言語を使用できると嬉しいという気持ちが暗に込められています。 ↩
-
ここで紹介したフレームワークには「HTMLファイルを静的に生成する」ためのツールがあるらしく、HTMLテンプレートエンジンと同様の使い方ができるかもしれません(詳細はあまり把握していません)。 ↩