EJSを使う機会があったので、準備の手順をまとめます。EJSは、HTMLの中にJavaScriptを埋め込んで、ヘッダーやフッターなどの共通部分を部品として使い回せるテンプレートエンジンです。
Node.jsとnpmがインストール済みであることを前提とします。
この記事のコードは、gulp 5.0.1、gulp-ejs 5.1.0、gulp-prettier 7.0.0、Node.js 24で動作を確認しています(2026年10月時点)。
package.jsonの作成とパッケージのインストール
package.jsonを作成
npm init -yインストールするパッケージ
続いて、EJSのコンパイルに必要なnpmのパッケージをインストールします。
パッケージ | 役割 |
|---|---|
gulp | タスクランナー |
gulp-ejs | EJSのコンパイル |
gulp-rename | コンパイル時に拡張子を.ejsから.htmlに変える |
gulp-plumber | エラーが出ても処理を停止しない |
gulp-notify | エラーの内容を通知する |
gulp-prettier | HTMLを整形する |
下記のコマンドでまとめてインストールできます。
npm i -D gulp gulp-rename gulp-ejs gulp-notify gulp-plumber gulp-prettier以下のコマンドを実行して、gulpが使える状態か確認してください。
npx gulp --versionnpxを付けると、プロジェクトにインストールしたgulpを実行できます。npxを付けずにgulpコマンドを使いたい場合は、npm i --global gulp-cliでgulp-cliをインストールしてください。
ファイルを作成する
gulpfile.jsにタスクを書く
プロジェクトの直下にgulpfile.jsを作成し、下記のコードを貼り付けます。
const { src, dest, watch, series } = require('gulp')const rename = require('gulp-rename')const ejs = require('gulp-ejs')const notify = require('gulp-notify')const plumber = require('gulp-plumber')const prettier = require('gulp-prettier').default// EJSをHTMLにコンパイルするconst ejsFunc = () => { return src(['./src/ejs/**/*.ejs', '!./src/ejs/**/_*.ejs']) .pipe( plumber({ errorHandler: notify.onError('Error: <%= error.message %>'), }), ) .pipe(ejs()) .pipe(rename({ extname: '.html' })) .pipe( prettier({ printWidth: 150, semi: true, singleQuote: true, trailingComma: 'all', }), ) .pipe(dest('./'))}// ファイルを監視するconst watchFiles = () => { watch('./src/ejs/**/*.ejs', ejsFunc)}exports.ejs = ejsFuncexports.watch = watchFilesexports.default = series(ejsFunc, watchFiles)ファイル名が_で始まるEJS(_header.ejsなど)は、ほかのファイルから読み込む部品として扱い、単体ではHTMLに出力しません。
現在のgulp-prettier(バージョン7)はESモジュールです。requireで読み込む場合は、require('gulp-prettier').defaultのように.defaultを付けます。付けないと「prettier is not a function」というエラーになります。
EJSファイルを作成する
index.ejs、_header.ejs、_footer.ejsにコードを書きます。
<% let title = "トップページのタイトル" %><%- include('common/_header', { ttl: title }) %> <p>ページの本文</p><%- include('common/_footer') %><!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title><%= ttl %></title></head><body></body></html><%- include() %>で別のファイルを読み込みます。第2引数に渡した値(ここではttl)は、読み込まれた側で使えます。<%= %>は値をエスケープして出力し、<%- %>はエスケープせずに出力します。
コンパイルしてみる
gulpfile.jsには、2つのタスクが書かれています。
1度だけコンパイル
npx gulp ejsファイルを監視してコンパイル
EJSファイルを保存するたびに、自動でコンパイルします。止めるときはCtrl + Cを押します。
npx gulp watch出力されたHTMLを見てみる
前述のgulpfile.jsをそのまま貼り付けた場合、プロジェクトの直下にindex.htmlが生成されるので、その中身を確認してみます。gulp-prettierによって整形されたHTMLが出力されます。
<!doctype html><html lang="ja"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>トップページのタイトル</title> </head> <body> <p>ページの本文</p> </body></html>JSONを使用する場合の追加対応
サイト名などのデータをJSONファイルにまとめておき、テンプレートの中で使うこともできます。JSONファイルを読み込んで、ejs()の引数に渡します。JSONファイルを変更したときもコンパイルするように、監視の対象にも加えます。
const { src, dest, watch, series } = require('gulp')const rename = require('gulp-rename')const ejs = require('gulp-ejs')const notify = require('gulp-notify')const plumber = require('gulp-plumber')const prettier = require('gulp-prettier').defaultconst fs = require('fs')// EJSをHTMLにコンパイルするconst ejsFunc = () => { const jsonData = JSON.parse(fs.readFileSync('./src/ejs/json/data.json')) return src(['./src/ejs/**/*.ejs', '!./src/ejs/**/_*.ejs']) .pipe( plumber({ errorHandler: notify.onError('Error: <%= error.message %>'), }), ) .pipe(ejs({ jsonData: jsonData })) .pipe(rename({ extname: '.html' })) .pipe( prettier({ printWidth: 150, semi: true, singleQuote: true, trailingComma: 'all', }), ) .pipe(dest('./'))}// ファイルを監視するconst watchFiles = () => { watch(['./src/ejs/**/*.{ejs,json}'], ejsFunc)}exports.ejs = ejsFuncexports.watch = watchFilesexports.default = series(ejsFunc, watchFiles){ "siteName": "サイト名"}テンプレートの中では、jsonDataからデータを取り出せます。
<p><%= jsonData.siteName %></p>まとめ
HTMLを効率よく書きたいときに、EJSや他のテンプレートエンジンを使ってみると良いですね。