Express: Шаблонизаторы (EJS, Pug)

Шаблонизаторы (view engines) позволяют Express генерировать HTML на сервере, вставляя данные из JavaScript в шаблоны — альтернатива SPA-подходу (React, Vue) при Server-Side Rendering.

Зачем нужно

SSR через шаблонизаторы актуален для SEO-важных страниц, admin-панелей, почтовых писем и простых сайтов без необходимости в SPA. EJS использует синтаксис близкий к HTML, Pug — отступы вместо тегов. Оба поддерживают res.render из Express без дополнительной конфигурации.

Где используется

  • Admin-панели и CMS (быстрый SSR без React)
  • Генерация HTML-писем (nodemailer + шаблон)
  • Лендинги и контентные сайты (хорошая индексация)
  • Прототипирование — быстро показать UI без фронтенда

Основной контент

Настройка Express

const express = require('express');
const path = require('path');
const app = express;

// Указать шаблонизатор
app.set('view engine', 'ejs'); // или 'pug'
// Директория с шаблонами (по умолчанию views/)
app.set('views', path.join(__dirname, 'views'));

EJS — установка и синтаксис

npm install ejs
<!-- views/index.ejs -->
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
  <h1><%= title %></h1>

  <!-- Условие -->
  <% if (user) { %>
    <p>Привет, <%= user.name %>!</p>
  <% } else { %>
    <a href="/login">Войти</a>
  <% } %>

  <!-- Цикл -->
  <ul>
    <% items.forEach(item => { %>
      <li><%= item.name %> — <%= item.price %> руб.</li>
    <% }) %>
  </ul>

  <!-- Подключение partial -->
  <%- include('partials/footer') %>
</body>
</html>

Pug — установка и синтаксис

npm install pug
//- views/index.pug
doctype html
html
  head
    title= title
  body
    h1= title

    if user
      p Привет, #{user.name}!
    else
      a(href='/login') Войти

    ul
      each item in items
        li #{item.name} — #{item.price} руб.

    include partials/footer

Рендеринг из маршрута

// Передаём данные в шаблон
app.get('/', async (req, res) => {
  const items = await ProductService.getAll;
  res.render('index', {
    title: 'Магазин',
    user: req.user || null,
    items
  });
});

// Render в строку (для писем)
app.get('/send-email', async (req, res) => {
  res.render('email/welcome', { name: 'Иван' }, (err, html) => {
    if (err) return next(err);
    // html — готовая строка
    mailer.send({ to: 'user@mail.com', html });
    res.json({ ok: true });
  });
});

Layouts (EJS Layouts)

npm install express-ejs-layouts
const ejsLayouts = require('express-ejs-layouts');
app.use(ejsLayouts);
app.set('layout', 'layouts/main'); // views/layouts/main.ejs
<!-- views/layouts/main.ejs -->
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
  <%- body %> <!-- сюда вставляется содержимое страницы -->
</body>
</html>

Частые ошибки

  • <%= %> vs <%- %><%= %> экранирует HTML (безопасно), <%- %> вставляет сырой HTML (XSS-уязвимость при пользовательских данных)
  • Пропустить app.set('view engine') — Express не знает какой шаблонизатор использовать, ошибка при res.render
  • Путь к views — по умолчанию относительно CWD процесса; всегда задавать path.join(__dirname, 'views')
  • Использовать шаблонизаторы для API — в REST API возвращают JSON, шаблонизаторы нужны только для SSR HTML

Связанные темы

Ресурсы