SPA: что такое и чем отличается от MPA

SPA (Single Page Application) загружает одну HTML-страницу и динамически обновляет контент через JavaScript без перезагрузки; MPA (Multi-Page Application) получает с сервера новую HTML-страницу при каждой навигации.

Зачем нужно

Понимание разницы SPA vs MPA — фундамент для выбора архитектуры проекта. Вопрос «делать ли SPA?» возникает в начале каждого проекта. Ошибка в выборе дорого стоит: SPA для SEO-зависимого контента потребует SSR-обёртки, а MPA для сложного интерактивного инструмента будет работать медленно.

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

  • SPA: веб-приложения с богатым UX (Gmail, Trello, Figma, Notion)
  • MPA: новостные сайты, блоги, e-commerce с SEO-требованиями
  • Гибрид (SPA + SSR): Next.js, Nuxt — лучшее из обоих миров
  • Постепенная миграция: компании переходят с MPA на SPA-части без полной переработки

SPA vs MPA

MPA (Multi-Page Application)
─────────────────────────────
Клик по ссылке
      ↓
Браузер → GET /about HTTP/1.1 → Сервер
                                    ↓
Сервер рендерит полную страницу
                                    ↓
Браузер получает новый HTML (300ms+)
                                    ↓
Страница перезагружается, белый экран

SPA (Single Page Application)
──────────────────────────────
Первый запрос: загрузка index.html + bundle.js
Клик по ссылке
      ↓
JS перехватывает (preventDefault)
      ↓
URL меняется через History API (мгновенно)
      ↓
React/Vue перерисовывает нужный компонент
      ↓
При необходимости: fetch('/api/data') → JSON
      ↓
Интерфейс обновляется без перезагрузки (~50ms)

Сравнительная таблица

Критерий SPA MPA
Первая загрузка Медленнее (JS bundle) Быстрее
Навигация Мгновенная Перезагрузка
SEO Требует настройки Нативно
Оффлайн-режим Возможен Нет
Кэширование Агрессивное Ограниченное
Сложность Выше Ниже
UX App-like Традиционный

Минимальный SPA без фреймворка

const app = document.getElementById('app');

const routes = {
  '/':  => `<h1>Главная</h1><a href="/about" data-link>О нас</a>`,
  '/about':  => `<h1>О нас</h1><a href="/" data-link>Назад</a>`,
  '/404':  => `<h1>Страница не найдена</h1>`,
};

function render(path) {
  const handler = routes[path] || routes['/404'];
  app.innerHTML = handler;
}

// Перехват кликов по ссылкам
document.addEventListener('click', (e) => {
  const link = e.target.closest('[data-link]');
  if (link) {
    e.preventDefault();
    history.pushState(null, '', link.href);
    render(window.location.pathname);
  }
});

// Кнопки Назад/Вперёд
window.addEventListener('popstate', () => {
  render(window.location.pathname);
});

render(window.location.pathname);

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

  • SPA для контент-сайтов без SSR — поисковики получают пустой HTML; добавляйте SSR или SSG.
  • Не настроен server fallback — при прямом заходе на /about сервер отдаёт 404; нужен redirect на index.html.
  • MPA там, где нужен SPA — форма с несколькими шагами на разных HTML-страницах теряет состояние при переходе.

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

Ресурсы