Стратегии рендеринга
Выбор стратегии рендеринга -- одно из ключевых архитектурных решений для веб-приложения. Каждая стратегия имеет свои компромиссы.
Обзор стратегий
Сервер Клиент
◀─────────────────────────────────────────▶
SSG SSR ISR Streaming CSR
│ │ │ SSR │
│ │ │ │ │
Статика Динамика Гибрид Потоковый SPA
Build Request Build+ Request Runtime
time time Revalid time (browser)
CSR (Client-Side Rendering)
Сервер отправляет пустой HTML, JavaScript загружается и рендерит контент в браузере.
Browser Server
│ │
│──── GET /page ───────────────▶│
│◀─── Empty HTML + JS bundle ──│
│ │
│ [Парсинг JS] │
│ [Выполнение JS] │
│ [Рендер DOM] │
│ │
│──── API requests ────────────▶│
│◀─── JSON data ───────────────│
│ │
│ [Обновление DOM] │
│ ✓ Страница готова │
| Плюсы | Минусы |
|---|---|
| Богатая интерактивность | Плохой SEO (пустой HTML) |
| Лёгкий сервер (статика) | Долгий Time to Interactive |
| Хорошо для SPA | Большой JS bundle |
| Простой деплой (CDN) | Зависимость от JS в браузере |
Когда использовать: Внутренние инструменты, дашборды, приложения за авторизацией, где SEO не важен.
SSR (Server-Side Rendering)
Сервер генерирует полный HTML на каждый запрос.
Browser Server
│ │
│──── GET /page ───────────────▶│
│ │ [Fetch data]
│ │ [Render HTML]
│◀─── Full HTML ───────────────│
│ │
│ [Отрисовка HTML] │
│ FCP ✓ (контент видим) │
│ │
│ [Загрузка JS] │
│ [Hydration] │
│ TTI ✓ (интерактивен) │
| Плюсы | Минусы |
|---|---|
| Отличный SEO | Нагрузка на сервер |
| Быстрый FCP | TTFB выше (сервер рендерит) |
| Персонализированный контент | Требует Node.js сервер |
| Актуальные данные | Не кешируется на CDN |
Когда использовать: E-commerce, новостные сайты, персонализированные страницы, SEO-критичные приложения.
SSG (Static Site Generation)
HTML генерируется на этапе сборки. Готовые файлы раздаются через CDN.
BUILD TIME:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Source │───▶│ Build │───▶│ Static │
│ (MD,API) │ │ Process │ │ Files │
└──────────┘ └──────────┘ └──────────┘
RUNTIME:
Browser CDN
│ │
│──── GET /page ───────────────▶│
│◀─── Pre-built HTML ─────────│ (< 50ms)
│ │
│ ✓ Мгновенный FCP │
| Плюсы | Минусы |
|---|---|
| Максимально быстрый TTFB | Данные устаревают |
| Идеальный для CDN | Долгий build при >10K страниц |
| Отличный SEO | Нет персонализации |
| Минимальная инфраструктура | Rebuild для обновления |
Когда использовать: Блоги, документация, лендинги, маркетинговые сайты.
ISR (Incremental Static Regeneration)
Гибрид SSG и SSR: статические страницы с фоновым обновлением.
Request 1 (cache fresh):
Browser ──▶ CDN ──▶ Cached HTML (мгновенно)
Request 2 (cache stale, revalidate = 60s):
Browser ──▶ CDN ──▶ Stale HTML (мгновенно)
│
└──▶ Background: Server рендерит новый HTML
Обновляет кеш для следующего запроса
Request 3 (после revalidation):
Browser ──▶ CDN ──▶ Fresh HTML (мгновенно)
| Плюсы | Минусы |
|---|---|
| Скорость SSG + актуальность SSR | Stale данные в окне revalidation |
| Не нужен rebuild всего сайта | Сложнее дебажить |
| Масштабируется через CDN | Не для real-time данных |
| On-demand revalidation | Vendor lock-in (Vercel/Next.js) |
Hydration
Hydration -- процесс "оживления" статического HTML: подключение event listeners, восстановление состояния.
Проблема Full Hydration
Server HTML: ████████████████████████ (отрисован, видим)
JS Bundle: ░░░░░░░░████████████████ (загружается)
Hydration: ░░░░░░░░░░░░░░██████████ (выполняется)
Interactive: ░░░░░░░░░░░░░░░░░░░░░░██ ← TTI (поздно!)
Проблема: пользователь видит контент, но не может
взаимодействовать, пока вся страница не гидратируется.
Виды Hydration
| Вид | Описание | Пример |
|---|---|---|
| Full Hydration | Гидратация всей страницы целиком | React SSR, Next.js (default) |
| Progressive Hydration | Гидратация по приоритету компонентов | React lazy + Suspense |
| Selective Hydration | Гидратация только видимых компонентов | React 18 Concurrent |
| Partial Hydration | Часть компонентов не гидратируется | Astro Islands |
| Resumable | Без повторного выполнения JS на клиенте | Qwik |
Streaming SSR
Streaming SSR -- сервер отправляет HTML частями (chunks) по мере готовности.
Traditional SSR:
Server: [─── fetch data ───][─── render all ───] → Full HTML
Streaming SSR:
Server: [── render shell ──] → <html><head>...
[── fetch data 1 ──] → <div>section 1</div>
[── fetch data 2 ──] → <div>section 2</div>
→ </html>
Browser получает контент по частям, рендерит мгновенно.
Преимущества Streaming SSR
| Аспект | Traditional SSR | Streaming SSR |
|---|---|---|
| TTFB | Ждёт всех данных | Мгновенный (shell) |
| FCP | После полного рендера | После первого chunk |
| Параллелизм | Нет (waterfall) | Параллельная загрузка |
| UX | Белый экран → полная страница | Постепенное появление |
Islands Architecture
Islands Architecture -- страница состоит из статического HTML (океан) с интерактивными компонентами (острова).
┌──────────────────────────────────────────────────┐
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Static Header (HTML) │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────┐ Static text ┌──────────────┐ │
│ │ ▪ Island │ and images │ ▪ Island │ │
│ │ Search │ (no JS) │ Carousel │ │
│ │ (Hydrated)│ │ (Hydrated) │ │
│ └──────────┘ └──────────────┘ │
│ │
│ More static content, no JavaScript needed │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ Static Footer (HTML) │ │
│ └──────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────┘
▪ = Interactive Island (hydrated, has JS)
Everything else = Static HTML (zero JS)
| Плюсы | Минусы |
|---|---|
| Минимум JavaScript | Ограниченное взаимодействие между островами |
| Быстрый TTI | Сложнее shared state |
| Отличная производительность | Не для SPA-подобных приложений |
| SEO-friendly | Парадигма отличается от привычных фреймворков |
Фреймворки: Astro, Fresh (Deno), Eleventy + Islands.
Сравнение стратегий
| Стратегия | TTFB | FCP | TTI | SEO | Динамика | Инфраструктура |
|---|---|---|---|---|---|---|
| CSR | Быстрый | Медленный | Медленный | Плохой | Полная | CDN |
| SSR | Средний | Быстрый | Средний | Отличный | Полная | Node.js сервер |
| SSG | Очень быстрый | Очень быстрый | Быстрый | Отличный | Нет | CDN |
| ISR | Очень быстрый | Очень быстрый | Быстрый | Отличный | Частичная | CDN + сервер |
| Streaming | Быстрый | Очень быстрый | Средний | Отличный | Полная | Node.js сервер |
| Islands | Очень быстрый | Очень быстрый | Очень быстрый | Отличный | Частичная | CDN |
Итоги
| Концепция | Суть |
|---|---|
| CSR | JS в браузере рендерит всё. Для SPA и внутренних приложений |
| SSR | Сервер генерирует HTML. SEO + персонализация |
| SSG | HTML на этапе сборки. Максимальная скорость |
| ISR | SSG + фоновое обновление. Баланс скорости и актуальности |
| Hydration | Оживление статического HTML. Узкое место производительности |
| Streaming SSR | HTML по частям. Быстрый FCP без ожидания |
| Islands | Минимум JS. Статика + интерактивные острова |
Главное правило: Нет универсальной стратегии. Выбирай по критериям: SEO, персонализация, частота обновлений, инфраструктурные ограничения.