この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:4
ページ更新者:guest
更新日時:2026-06-11 07:07:02

タイトル: テンプレートエンジン
SEOタイトル: テンプレートエンジン完全ガイド

この本文には実行可能なタグ等が含まれるため、安全のため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>テンプレートエンジン</strong> = HTML のひな形に変数や制御構文を埋め込み、動的に最終 HTML を生成する仕組み</li><li>サーバ側: <strong>Blade (Laravel) / Twig (Symfony) / Smarty (PHP)</strong>、<strong>Jinja2 (Python) / Django Templates</strong>、<strong>Thymeleaf (Java) / FreeMarker</strong>、<strong>EJS / Pug / Handlebars / Mustache (Node.js)</strong></li><li>クライアント側: <strong>Vue / React JSX / Svelte</strong> のテンプレート系</li><li>静的サイト生成 (SSG): <strong>Eleventy / Hugo / Gatsby / Astro</strong></li><li>主な利点: <strong>HTML エスケープの自動化</strong>、ロジックとビューの分離、コンパイル キャッシュで高速化、レイアウト継承で DRY</li></ul></td></tr></table>
<h2>テンプレートエンジンとは</h2>

<p>テンプレートエンジン (Template Engine) は、<strong>HTML のひな形 (テンプレート)</strong> に動的なデータを差し込み、最終的な HTML を生成するソフトウェアです。例えば「ユーザー名」だけが違う 1000 通りのページを、1 個のテンプレートと 1000 件のデータから生成できます。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!-- テンプレート (Blade) -->
<h1>こんにちは、{{ $user->name }}さん</h1>
<p>あなたの注文は {{ $orders->count() }} 件です。</p>

@foreach ($orders as $order)
  <li>{{ $order->title }} - {{ $order->price }}円</li>
@endforeach</code></pre>
<p>テンプレートエンジンを使わずに「素の PHP」で書くと <code><?php echo $user->name; ?></code> のように冗長になり、XSS 脆弱性を生みやすくなります。</p>

<h2>テンプレートエンジンの利点</h2>

<ul>
<li><strong>HTML エスケープの自動化</strong>: <code>{{ }}</code> で出力すると自動でエスケープされ XSS を防ぐ</li>
<li><strong>ロジックとビューの分離</strong>: コントローラはデータ取得、テンプレートは表示に集中</li>
<li><strong>レイアウト継承</strong>: 共通レイアウト (ヘッダ / フッタ) を 1 箇所で管理</li>
<li><strong>コンパイル キャッシュ</strong>: テンプレートを最適化された PHP/Python/Java コードに事前変換</li>
<li><strong>カスタムタグ / フィルタ</strong>: 日付フォーマット、通貨表示などを再利用可能に</li>
<li><strong>セキュリティ</strong>: 自動エスケープ + サンドボックスで安全</li>
</ul>

<h2>PHP のテンプレートエンジン</h2>

<h3>Blade (Laravel 標準)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-blade">{{-- layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head><title>@yield(&apos;title&apos;)</title></head>
<body>
  <nav>@include(&apos;partials.nav&apos;)</nav>
  <main>@yield(&apos;content&apos;)</main>
</body>
</html>

{{-- pages/article.blade.php --}}
@extends(&apos;layouts.app&apos;)

@section(&apos;title&apos;, $article->title)

@section(&apos;content&apos;)
  <h1>{{ $article->title }}</h1>          {{-- 自動エスケープ --}}
  {!! $article->html_content !!}          {{-- 生 HTML --}}

  @if ($user)
    <p>ようこそ {{ $user->name }} さん</p>
  @else
    <a href="/login">ログイン</a>
  @endif

  @foreach ($comments as $comment)
    <article>{{ $comment->body }}</article>
  @endforeach
@endsection</code></pre>
<h3>Twig (Symfony / 多言語)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-twig">{# layout.html.twig #}
<!DOCTYPE html>
<html>
<head><title>{% block title %}{% endblock %}</title></head>
<body>{% block content %}{% endblock %}</body>
</html>

{# article.html.twig #}
{% extends "layout.html.twig" %}

{% block title %}{{ article.title }}{% endblock %}

{% block content %}
  <h1>{{ article.title }}</h1>
  {{ article.body|raw }}                {# 生 HTML #}
  {{ now|date(&apos;Y-m-d&apos;) }}               {# フィルタ #}

  {% if user %}
    <p>{{ user.name }}</p>
  {% endif %}

  {% for comment in comments %}
    <p>{{ comment.body }}</p>
  {% endfor %}
{% endblock %}</code></pre>
<h3>Smarty (老舗 PHP)</h3>

<p>2001 年から続く老舗。EC サイト (EC-CUBE 等) で今も使われています。</p>

<h2>Python のテンプレートエンジン</h2>

<h3>Jinja2 (Flask 標準、Ansible でも使われる)</h3>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{# base.html #}
<!DOCTYPE html>
<html>
<body>{% block content %}{% endblock %}</body>
</html>

{# article.html #}
{% extends "base.html" %}
{% block content %}
  <h1>{{ article.title }}</h1>
  {{ article.body | safe }}        {# raw HTML #}

  {% if user %}
    <p>{{ user.name | upper }}</p>
  {% endif %}

  <ul>
  {% for c in comments %}
    <li>{{ c.body }}</li>
  {% else %}
    <li>コメント無し</li>
  {% endfor %}
  </ul>
{% endblock %}</code></pre>
<h3>Django Templates</h3>

<p>Django 標準。Jinja2 とほぼ同じ記法 (実は Jinja2 が Django Templates にインスパイアされた)。</p>

<h2>Java のテンプレートエンジン</h2>

<h3>Thymeleaf (Spring Boot 標準)</h3>

<p>HTML 属性として記述するので、テンプレート単体でブラウザで開いても表示が崩れないのが特徴。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html"><!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
  <h1 th:text="${article.title}">記事タイトル</h1>

  <div th:if="${user != null}">
    <p th:text="|ようこそ ${user.name} さん|"></p>
  </div>

  <ul>
    <li th:each="comment : ${comments}" th:text="${comment.body}"></li>
  </ul>

  <a th:href="@{/article/{id}(id=${article.id})}">詳細</a>
</body>
</html></code></pre>
<h3>FreeMarker</h3>

<p>Apache 系。柔軟性が高く、メール本文生成などにも使われます。</p>

<h2>Node.js のテンプレートエンジン</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>EJS</td><td>HTML に近い、PHP に似た記法</td><td><code><%= title %></code></td></tr>
<tr><td>Pug (旧 Jade)</td><td>インデントベース、簡潔</td><td><code>h1= title</code></td></tr>
<tr><td>Handlebars</td><td>ロジックレス指向、Mustache 拡張</td><td><code>{{title}}</code></td></tr>
<tr><td>Mustache</td><td>言語非依存、ロジックレス</td><td><code>{{title}}</code></td></tr>
<tr><td>Nunjucks</td><td>Mozilla 製、Jinja2 ライク</td><td><code>{{ title }}</code></td></tr>
</tbody>
</table>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// EJS の例
const ejs = require(&apos;ejs&apos;);
const html = ejs.render(`
  <h1><%= article.title %></h1>
  <% if (user) { %>
    <p><%= user.name %></p>
  <% } %>
`, { article, user });

// Handlebars の例
const Handlebars = require(&apos;handlebars&apos;);
const template = Handlebars.compile(`
  <h1>{{ article.title }}</h1>
  {{#if user}}
    <p>{{ user.name }}</p>
  {{/if}}
  {{#each comments}}
    <p>{{ this.body }}</p>
  {{/each}}
`);
const html2 = template({ article, user, comments });</code></pre>
<h2>クライアントサイド (Vue / React / Svelte)</h2>

<p>SPA (Single Page Application) ではフロント側にもテンプレート機構があります。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-vue"><!-- Vue.js -->
<template>
  <h1>{{ article.title }}</h1>
  <p v-if="user">ようこそ {{ user.name }}</p>
  <ul>
    <li v-for="c in comments" :key="c.id">{{ c.body }}</li>
  </ul>
</template>

<script setup>
import { ref } from &apos;vue&apos;;
const article = ref({ title: &apos;...&apos; });
</script></code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-jsx">// React JSX
function Article({ article, user, comments }) {
  return (
    <>
      <h1>{article.title}</h1>
      {user && <p>ようこそ {user.name}</p>}
      <ul>
        {comments.map(c => <li key={c.id}>{c.body}</li>)}
      </ul>
    </>
  );
}</code></pre>
<h2>静的サイトジェネレータ (SSG)</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><th>用途</th></tr></thead>
<tbody>
<tr><td>Hugo</td><td>Go</td><td>Go templates</td><td>高速ブログ、ドキュメント</td></tr>
<tr><td>Eleventy (11ty)</td><td>Node.js</td><td>Nunjucks/Liquid/EJS/Markdown</td><td>軽量ブログ</td></tr>
<tr><td>Jekyll</td><td>Ruby</td><td>Liquid</td><td>GitHub Pages</td></tr>
<tr><td>Gatsby</td><td>React</td><td>JSX + GraphQL</td><td>React 派生</td></tr>
<tr><td>Next.js (SSG モード)</td><td>React</td><td>JSX</td><td>React + ISR</td></tr>
<tr><td>Astro</td><td>多言語</td><td>独自 + Vue/React/Svelte 混在</td><td>パフォーマンス重視ブログ</td></tr>
<tr><td>VitePress / Docusaurus</td><td>Vue / React</td><td>各々</td><td>ドキュメント</td></tr>
</tbody>
</table>

<h2>Plain PHP vs テンプレートエンジン</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php"><?php // Plain PHP - 動くが推奨されない ?>
<h1><?= htmlspecialchars($title) ?></h1>
<?php if ($user): ?>
  <p>こんにちは <?= htmlspecialchars($user->name) ?></p>
<?php endif; ?>
<ul>
<?php foreach ($items as $item): ?>
  <li><?= htmlspecialchars($item) ?></li>
<?php endforeach; ?>
</ul>

<?php // Blade - 推奨 ?>
<h1>{{ $title }}</h1>
@if ($user)
  <p>こんにちは {{ $user->name }}</p>
@endif
<ul>
  @foreach ($items as $item)
    <li>{{ $item }}</li>
  @endforeach
</ul></code></pre>
<h2>コンパイル キャッシュの仕組み</h2>

<p>多くのテンプレートエンジンは、テンプレートを<strong>1 度だけパースして最適化された PHP/Java/JS コードに変換</strong>し、ファイルとしてキャッシュします。2 度目以降はキャッシュを読むだけなので高速です。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Laravel Blade のキャッシュ場所:
  storage/framework/views/*.php

Twig のキャッシュ:
  var/cache/dev/twig/

Thymeleaf:
  メモリ上にコンパイル済テンプレート保持

# 開発時はキャッシュ無効化、本番では有効化
# Laravel: APP_DEBUG=false で自動キャッシュ</code></pre>
<h2>選定ガイド</h2>

<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e8f5e9"><th>状況</th><th>推奨</th></tr></thead>
<tbody>
<tr><td>Laravel プロジェクト</td><td>Blade (標準で十分強力)</td></tr>
<tr><td>Symfony / 純 PHP</td><td>Twig</td></tr>
<tr><td>Spring Boot</td><td>Thymeleaf (公式チュートリアル基準)</td></tr>
<tr><td>Django</td><td>Django Templates (標準)</td></tr>
<tr><td>Flask</td><td>Jinja2 (標準)</td></tr>
<tr><td>Express.js</td><td>EJS / Pug、両方人気</td></tr>
<tr><td>静的サイト (高速重視)</td><td>Hugo</td></tr>
<tr><td>静的サイト (柔軟性重視)</td><td>Astro / Eleventy</td></tr>
<tr><td>SPA</td><td>React JSX / Vue Template / Svelte</td></tr>
</tbody>
</table>

<h2>FAQ</h2>

<p><strong>Q: テンプレートエンジンを使わず素の PHP/Node でも書けるが、なぜ使う?</strong><br />
A: 自動エスケープ、レイアウト継承、可読性、保守性、IDE 補完、コンパイルキャッシュ、開発者間の共通認識。長期保守を考えれば導入する価値があります。</p>

<p><strong>Q: ロジックをテンプレート側に書いてもよい?</strong><br />
A: 表示に関する分岐 (if/for) は OK。ビジネスロジック (DB 操作、計算) はコントローラやサービス層に置くべき。<strong>「テンプレートは表示専用」</strong>を意識します。</p>

<p><strong>Q: パフォーマンスはどれが速い?</strong><br />
A: コンパイルキャッシュが効けば差は僅かです。Hugo (Go) はビルド速度が非常に速いことで有名。サーバ側は <strong>適切なキャッシュ設定が最重要</strong>で、エンジン選定の差は通常無視できます。</p>