5.

テンプレートエンジン完全ガイド

編集
この記事の要点
  • テンプレートエンジン = HTML のひな形に変数や制御構文を埋め込み、動的に最終 HTML を生成する仕組み
  • サーバ側: Blade (Laravel) / Twig (Symfony) / Smarty (PHP)Jinja2 (Python) / Django TemplatesThymeleaf (Java) / FreeMarkerEJS / Pug / Handlebars / Mustache (Node.js)
  • クライアント側: Vue / React JSX / Svelte のテンプレート系
  • 静的サイト生成 (SSG): Eleventy / Hugo / Gatsby / Astro
  • 主な利点: HTML エスケープの自動化、ロジックとビューの分離、コンパイル キャッシュで高速化、レイアウト継承で DRY

テンプレートエンジンとは

テンプレートエンジン (Template Engine) は、HTML のひな形 (テンプレート) に動的なデータを差し込み、最終的な HTML を生成するソフトウェアです。例えば「ユーザー名」だけが違う 1000 通りのページを、1 個のテンプレートと 1000 件のデータから生成できます。

<!-- テンプレート (Blade) -->
<h1>こんにちは、{{ $user->name }}さん</h1>
<p>あなたの注文は {{ $orders->count() }} 件です。</p>

@foreach ($orders as $order)
  <li>{{ $order->title }} - {{ $order->price }}円</li>
@endforeach

テンプレートエンジンを使わずに「素の PHP」で書くと <?php echo $user->name; ?> のように冗長になり、XSS 脆弱性を生みやすくなります。

テンプレートエンジンの利点

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

PHP のテンプレートエンジン

Blade (Laravel 標準)

{{-- layouts/app.blade.php --}}
<!DOCTYPE html>
<html>
<head><title>@yield('title')</title></head>
<body>
  <nav>@include('partials.nav')</nav>
  <main>@yield('content')</main>
</body>
</html>

{{-- pages/article.blade.php --}}
@extends('layouts.app')

@section('title', $article->title)

@section('content')
  <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

Twig (Symfony / 多言語)

{# 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('Y-m-d') }}               {# フィルタ #}

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

  {% for comment in comments %}
    <p>{{ comment.body }}</p>
  {% endfor %}
{% endblock %}

Smarty (老舗 PHP)

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

Python のテンプレートエンジン

Jinja2 (Flask 標準、Ansible でも使われる)

{# 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 %}

Django Templates

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

Java のテンプレートエンジン

Thymeleaf (Spring Boot 標準)

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>

FreeMarker

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

Node.js のテンプレートエンジン

エンジン特徴
EJSHTML に近い、PHP に似た記法<%= title %>
Pug (旧 Jade)インデントベース、簡潔h1= title
Handlebarsロジックレス指向、Mustache 拡張{{title}}
Mustache言語非依存、ロジックレス{{title}}
NunjucksMozilla 製、Jinja2 ライク{{ title }}
// EJS の例
const ejs = require('ejs');
const html = ejs.render(`
  <h1><%= article.title %></h1>
  <% if (user) { %>
    <p><%= user.name %></p>
  <% } %>
`, { article, user });

// Handlebars の例
const Handlebars = require('handlebars');
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 });

クライアントサイド (Vue / React / Svelte)

SPA (Single Page Application) ではフロント側にもテンプレート機構があります。

<!-- 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 'vue';
const article = ref({ title: '...' });
</script>
// 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>
    </>
  );
}

静的サイトジェネレータ (SSG)

ツール言語テンプレート用途
HugoGoGo templates高速ブログ、ドキュメント
Eleventy (11ty)Node.jsNunjucks/Liquid/EJS/Markdown軽量ブログ
JekyllRubyLiquidGitHub Pages
GatsbyReactJSX + GraphQLReact 派生
Next.js (SSG モード)ReactJSXReact + ISR
Astro多言語独自 + Vue/React/Svelte 混在パフォーマンス重視ブログ
VitePress / DocusaurusVue / React各々ドキュメント

Plain PHP vs テンプレートエンジン

<?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>

コンパイル キャッシュの仕組み

多くのテンプレートエンジンは、テンプレートを1 度だけパースして最適化された PHP/Java/JS コードに変換し、ファイルとしてキャッシュします。2 度目以降はキャッシュを読むだけなので高速です。

Laravel Blade のキャッシュ場所:
  storage/framework/views/*.php

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

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

# 開発時はキャッシュ無効化、本番では有効化
# Laravel: APP_DEBUG=false で自動キャッシュ

選定ガイド

状況推奨
Laravel プロジェクトBlade (標準で十分強力)
Symfony / 純 PHPTwig
Spring BootThymeleaf (公式チュートリアル基準)
DjangoDjango Templates (標準)
FlaskJinja2 (標準)
Express.jsEJS / Pug、両方人気
静的サイト (高速重視)Hugo
静的サイト (柔軟性重視)Astro / Eleventy
SPAReact JSX / Vue Template / Svelte

FAQ

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

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

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

編集
Post Share
子ページ
  1. JSP
  2. eRuby
同階層のページ
  1. 環境構築
  2. 文法
  3. 要素一覧
  4. API
  5. テンプレートエンジン
  6. <head>タグに書いた内容が<body>タグに移動する場合の解決方法
  7. 空白(スペース)の入力方法
  8. テキスト/セレクトボックス/ラジオボタン変更時のJS関数呼び出し
  9. buttonでformをsubmitさせない方法

最近更新/作成されたページ