タイトル: EJS
SEOタイトル: EJS 完全ガイド — Node.js テンプレートエンジン
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>EJS (Embedded JavaScript)</strong> は Node.js / Express で広く使われるテンプレートエンジン</li><li>記法はシンプル: <code><%= var %></code> エスケープ出力、<code><%- var %></code> 生 HTML 出力、<code><% if/for %></code> 制御</li><li>部分テンプレート (partial) は <code><%- include("header", { user }) %></code></li><li>Express で利用: <code>app.set("view engine", "ejs")</code> + <code>views/</code> ディレクトリに <code>.ejs</code> 配置</li><li>Handlebars / Pug / Mustache と比較すると <strong>素の JavaScript が書ける</strong>のが最大の特徴</li></ul></td></tr></table>
<h2>EJS とは</h2>
<p>EJS (Embedded JavaScript templating) は Node.js 用のテンプレートエンジンの一つです。HTML に <code><% %></code> で JavaScript を埋め込めるシンプルな構文が特徴で、PHP や ERB (Ruby) に近い感覚で書けます。</p>
<ul>
<li>軽量 (依存ライブラリほぼゼロ)</li>
<li>独自 DSL がなく <strong>素の JavaScript が書ける</strong></li>
<li>Express の標準的なテンプレートエンジンとして長年使われている</li>
<li>クライアントサイドでも動く (browserify / webpack)</li>
</ul>
<h2>インストール</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-bash">npm install ejs
# Express プロジェクトの場合
npm install express ejs</code></pre>
<h2>基本構文</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>タグ</th><th>用途</th><th>例</th></tr></thead>
<tbody>
<tr><td><code><%= var %></code></td><td>HTML エスケープ出力</td><td><code><%= user.name %></code></td></tr>
<tr><td><code><%- var %></code></td><td>生 HTML 出力 (XSS 注意)</td><td><code><%- post.bodyHtml %></code></td></tr>
<tr><td><code><% code %></code></td><td>JS 実行 (出力なし)</td><td><code><% if (user) { %></code></td></tr>
<tr><td><code><%# comment %></code></td><td>コメント</td><td><code><%# このブロックは ... %></code></td></tr>
<tr><td><code><%_ ... _%></code></td><td>前後の空白除去</td><td>整形用</td></tr>
<tr><td><code><%% / %%></code></td><td>リテラル <code><%</code> / <code>%></code></td><td>EJS 構文を文字として書きたい</td></tr>
</tbody>
</table>
<h2>サンプルテンプレート</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- views/users.ejs -->
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title><%= title %></title>
</head>
<body>
<h1><%= title %></h1>
<% if (users.length === 0) { %>
<p>ユーザーが登録されていません。</p>
<% } else { %>
<ul>
<% users.forEach(function(user) { %>
<li>
<%= user.name %> (<%= user.email %>)
<% if (user.isAdmin) { %>
<span class="badge">管理者</span>
<% } %>
</li>
<% }); %>
</ul>
<% } %>
<%- include('partials/footer') %>
</body>
</html></code></pre>
<h2>Express での利用</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// app.js
const express = require('express');
const path = require('path');
const app = express();
// テンプレートエンジン設定
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.get('/users', (req, res) => {
const users = [
{ name: '田中', email: 'tanaka@example.com', isAdmin: true },
{ name: '佐藤', email: 'sato@example.com', isAdmin: false },
];
res.render('users', { title: 'ユーザー一覧', users });
});
app.listen(3000);</code></pre>
<p>これで <code>views/users.ejs</code> がレンダリングされ、HTML として返されます。</p>
<h2>部分テンプレート (Partials / Include)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- views/partials/header.ejs -->
<header>
<nav>
<a href="/">トップ</a>
<% if (user) { %>
<a href="/logout">ログアウト (<%= user.name %>)</a>
<% } else { %>
<a href="/login">ログイン</a>
<% } %>
</nav>
</header>
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<body>
<%- include('partials/header', { user: currentUser }) %>
<main>...</main>
<%- include('partials/footer') %>
</body>
</html></code></pre>
<p><strong>注意</strong>: <code>include</code> は <code><%-</code> (生 HTML 出力) を使います。<code><%=</code> だとパーシャルの HTML がエスケープされてしまいます。</p>
<h2>レイアウト (express-ejs-layouts)</h2>
<p>EJS 本体にレイアウト機能はありませんが、<code>express-ejs-layouts</code> パッケージで実現可能:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">const expressLayouts = require('express-ejs-layouts');
app.use(expressLayouts);
app.set('layout', 'layouts/main'); // views/layouts/main.ejs</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- views/layouts/main.ejs -->
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
<%- body %> <!-- 子ビューがここに展開される -->
</body>
</html></code></pre>
<h2>クライアントサイドでの利用</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><script src="https://cdn.jsdelivr.net/npm/ejs@3.1.10/ejs.min.js"></script>
<script>
const template = '<h1>Hello, <%= name %>!</h1>';
const html = ejs.render(template, { name: 'World' });
document.body.innerHTML = html;
</script></code></pre>
<h2>他テンプレートエンジンとの比較</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>エンジン</th><th>記法</th><th>特徴</th></tr></thead>
<tbody>
<tr><td><strong>EJS</strong></td><td>HTML + <code><% %></code></td><td>素 JS が書ける。学習コスト最小</td></tr>
<tr><td>Pug (Jade)</td><td>インデント DSL</td><td>HTML タグ不要。簡潔だが独自構文</td></tr>
<tr><td>Handlebars</td><td><code>{{ var }}</code></td><td>logic-less。helper 関数で拡張</td></tr>
<tr><td>Mustache</td><td><code>{{ var }}</code></td><td>多言語対応。Handlebars の親</td></tr>
<tr><td>Nunjucks</td><td>Jinja2 風</td><td>Python 経験者になじむ</td></tr>
<tr><td>Liquid</td><td>Shopify 由来</td><td>EC サイト系で多用</td></tr>
</tbody>
</table>
<h2>セキュリティ注意点</h2>
<ul>
<li><code><%- userInput %></code> は <strong>XSS の温床</strong>。ユーザー入力は必ず <code><%= %></code></li>
<li>HTML サニタイズが必要なら <code>DOMPurify</code> や <code>sanitize-html</code> を併用</li>
<li><code>ejs.render(req.body.template, ...)</code> 等、ユーザー入力をテンプレート文字列にすると<strong>任意コード実行</strong>になる</li>
</ul>
<h2>FAQ</h2>
<p><strong>Q: <code><%= %></code> と <code><%- %></code> の使い分けは?</strong><br />
A: ユーザー入力 / DB 値は <code><%= %></code> (エスケープ)。WYSIWYG エディタで書いた既知の安全な HTML は <code><%- %></code>。</p>
<p><strong>Q: EJS は今でも現役?</strong><br />
A: Express のサンプルでは現役。ただし SSR は Next.js / Remix、SPA は React / Vue の時代なので、新規 Web アプリで EJS 一択というケースは減っています。</p>
<p><strong>Q: HTML の syntax highlight が効かない</strong><br />
A: VSCode なら <code>EJS language support</code> 拡張、または <code>files.associations</code> で <code>"*.ejs": "html"</code> を設定。</p>