SSR vs CSR — производительность

SSR (Server-Side Rendering) генерирует HTML на сервере при каждом запросе; CSR (Client-Side Rendering) отдаёт пустой HTML и рендерит контент через JavaScript в браузере. Выбор влияет на FCP, LCP, TTI и SEO.

Зачем нужно

Правильный выбор стратегии рендеринга принципиален для производительности: CSR плохо работает на медленных устройствах и ухудшает LCP, SSR увеличивает нагрузку на сервер и TTFB. Современные фреймворки предлагают гибридные стратегии (SSG, ISR, RSC).

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

  • SSR: контент-сайты, e-commerce, SEO-критичные страницы, personalized content
  • CSR: dashboard, admin-панели, приложения после логина
  • SSG: блоги, документация, маркетинг (статический контент)
  • ISR/RSC: Next.js, Astro — гибридный подход

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

Сравнение стратегий

CSR (Client-Side Rendering):
  TTFB     → Быстрый (статический shell)
  FCP      → Медленный (нужен JS для контента)
  LCP      → Медленный (данные после JS)
  TTI      → Медленный (hydration + data fetching)
  SEO      → Сложно (требует prerendering)
  Сервер   → Дешёвый (только статика)

SSR (Server-Side Rendering):
  TTFB     → Медленнее (генерация HTML)
  FCP      → Быстрый (HTML с контентом сразу)
  LCP      → Быстрый (контент в первом HTML)
  TTI      → После hydration (может быть долго)
  SEO      → Отличное (HTML с контентом)
  Сервер   → Дорогой (генерация на каждый запрос)

SSG (Static Site Generation):
  TTFB     → Минимальный (CDN)
  FCP/LCP  → Максимально быстрый
  SEO      → Отличное
  Данные   → Только статичные (без персонализации)

Waterfall проблема в CSR

CSR waterfall:
  0ms    → HTML получен (пустой)
  100ms  → JS бандл начал загрузку
  800ms  → JS выполнен, React инициализирован
  900ms  → API запрос за данными
  1400ms → Данные получены, контент отрендерен
  ↑ LCP = 1400ms

SSR:
  0ms    → Запрос к серверу
  200ms  → HTML с контентом получен (TTFB)
  ↑ FCP/LCP = 200ms + render time

Next.js: выбор стратегии per page

// SSG — статическая генерация (по умолчанию в App Router)
// Генерируется один раз при сборке
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug);
  return <Article post={post} />;
}

// SSR — динамический рендеринг при каждом запросе
export const dynamic = 'force-dynamic'; // Next.js 13+
// или
export const revalidate = 0;

// ISR — Incremental Static Regeneration (обновление каждые N секунд)
export const revalidate = 3600; // Обновлять каждый час

Гидрация и TTI

// Проблема: SSR контент виден, но не интерактивен до гидрации
// Пользователь видит кнопку и кликает — ничего не происходит

// Решение: прогрессивная гидрация (Islands Architecture)
// Гидрировать только интерактивные части, остальное — чистый HTML

// React 18: Selective Hydration
<Suspense fallback={<Skeleton />}>
  <Comments /> {/* Гидрируется позже, не блокирует остальное */}
</Suspense>

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

  • CSR для маркетинговых и SEO-критичных страниц — поисковики видят пустой HTML
  • SSR для всего приложения — высокая нагрузка сервера, медленный TTFB при высоком трафике
  • Гидрация без Suspense — блокирует TTI для всей страницы
  • Смешение персонализированного и кешируемого контента в одном SSR запросе

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

Ресурсы