В современной веб-разработке производительность и пользовательский опыт стали критически важными факторами успеха приложения. За последние годы мы прошли путь от классического клиентского рендеринга к сложным гибридным моделям. В этой статье мы разберем ключевые концепции, которые должен понимать каждый frontend-разработчик.
1. CSR (Client-Side Rendering) - Клиентский рендеринг.
Что это: Полностью браузерный рендеринг. Сервер отдает практически пустой HTML-файл с подключенными JavaScript-библиотеками, а браузер скачивает, парсит и выполняет JavaScript, который затем рендерит интерфейс.
<!-- Типичный index.html в CSR приложении -->
<!DOCTYPE html>
<html>
<head>
<title>Мое приложение</title>
</head>
<body>
<div id="root"></div> <!-- Пустой контейнер -->
<script src="bundle.js"></script> <!-- Весь код тут -->
</body>
</html>
Плюсы:
- Богатая интерактивность после загрузки
- Плавные переходы между страницами (SPA)
- Минимальная нагрузка на сервер
Минусы:
- Долгая первоначальная загрузка (белый экран)
- Плохая SEO (поисковики видят пустую страницу)
- Зависимость от JavaScript
Когда использовать: Админки, дашборды, приложения, где SEO неважен.
2. SSR (Server-Side Rendering) - Серверный рендеринг
Что это: Классический подход, где сервер генерирует полный HTML для каждой страницы и отдает его браузеру в готовом виде.
// Express.js пример SSR
app.get('/product/:id', (req, res) => {
const product = getProductFromDB(req.params.id);
const html = `
<html>
<head><title>${product.name}</title></head>
<body>
<h1>${product.name}</h1>
<p>${product.description}</p>
<!-- Готовый HTML сразу -->
</body>
</html>
`;
res.send(html);
});
Плюсы:
- Мгновенный первый контент (no white screen)
- Идеальная SEO-оптимизация
- Работает без JavaScript
Минусы:
- Медленный TTFB (Time To First Byte) при сложной логике
- Высокая нагрузка на сервер
- Меньше интерактивности
3. SSG (Static Site Generation) - Статическая генерация
Что это: HTML генерируется на этапе сборки и раздается как статические файлы.
// Next.js пример SSG
export async function getStaticProps() {
const products = await getAllProducts();
return {
props: { products },
revalidate: 3600 // ISR: перегенерировать раз в час
};
}
export default function HomePage({ products }) {
return (
<div>
{products.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Плюсы:
- Молниеносная загрузка (CDN)
- Бесплатная хостинг (GitHub Pages, Netlify)
- Идеальная безопасность (нет сервера)
Минусы:
- Нет динамических данных без пересборки
- Долгая сборка для больших сайтов
4. ISR (Incremental Static Regeneration) - Инкрементальная статическая регенерация
Что это: Продвинутая версия SSG, где страницы могут обновляться постфактум без полной пересборки.
Как работает:
- При первом запросе генерируется и кэшируется страница
- Последующие запросы получают кэшированную версию
- В фоне запускается регенерация по расписанию или триггеру
- Новая версия заменяет старую для следующих пользователей
Пример сценария:
- Блог: новые статьи добавляются без пересборки всего сайта
- Каталог товаров: цены обновляются раз в час
- Новостной сайт: главная страница обновляется каждые 5 минут
5. Core Web Vitals - Ключевые показатели производительности
Google ввел три ключевых метрики для оценки пользовательского опыта:
LCP (Largest Contentful Paint) - Загрузка самого большого элемента
Мера скорости загрузки. Должен быть менее 2.5 секунд.
// Оптимизации для LCP:
// 1. Предзагрузка ключевых ресурсов
<link rel="preload" href="hero-image.jpg" as="image">
// 2. Оптимизация изображений
<img src="image.jpg" loading="lazy" width="800" height="600">
// 3. Минимизация блокирующего CSS/JS
FID (First Input Delay) - Задержка первого ввода
Мера отзывчивости. Должен быть менее 100 мс.
// Улучшение FID:
// 1. Разделение кода на чанки
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
// 2. Отложенная загрузка не критичного JS
// 3. Веб-воркеры для тяжелых вычислений
CLS (Cumulative Layout Shift) - Совокупное смещение макета
Мера визуальной стабильности. Должен быть менее 0.1.
<!-- Предотвращение CLS: -->
<img width="300" height="200" src="image.jpg">
<!-- Всегда указывать размеры! -->
<div style="min-height: 300px;">
<!-- Резервируем место для лениво грузящегося контента -->
</div>
6. Гидрация (Hydration) - "Оживление" статического HTML
Что это: Процесс, когда React "оживляет" статический HTML, добавляя к нему интерактивность.
// После SSR/SSG мы получаем статический HTML:
<div id="root">
<button>Нажми меня</button> <!-- Статическая кнопка -->
</div>
// React гидратирует, добавляя обработчики:
<div id="root">
<button onClick={() => console.log('Clicked!')}>
Нажми меня
</button>
</div>
Проблема традиционной гидрации:
- Блокирует главный поток
- Может быть медленной на слабых устройствах
- Перегидрация всего приложения при навигации
7. Прогрессивная гидрация (Progressive Hydration)
Что это: Умная гидрация, которая происходит частями, а не всей страницей сразу.
Как работает:
- Критические компоненты гидратируются сразу
- Невидимые/неинтерактивные компоненты откладываются
- Гидрация по приоритету или при взаимодействии
// Пример с React 18 и Suspense
function App() {
return (
<div>
{/* Критичный компонент */}
<CriticalSection />
{/* Отложенная гидрация */}
<Suspense fallback={<Spinner />}>
<HeavyInteractiveComponent />
</Suspense>
{/* Гидрация по видимости */}
<Suspense fallback={<Placeholder />}>
<LazyComponent />
</Suspense>
</div>
);
}
Преимущества:
- Улучшенный TTI (Time To Interactive)
- Меньше блокировок главного потока
- Более плавный пользовательский опыт
8. Island Architecture (Архитектура "Островов")
Что это: Парадигма, где страница состоит из независимых "островов" интерактивности в море статического HTML.
// Пример с Astro.js (поддерживает Island Architecture)
---
// Статический компонент
import ProductCard from '../components/ProductCard.astro'
// Интерактивный "остров"
import CartCounter from '../components/CartCounter.jsx'
---
<div class="product-page">
<!-- Статическая часть -->
<ProductCard product={product} />
<!-- Интерактивный "остров" -->
<CartCounter client:load /> <!-- Загружается с приоритетом -->
<!-- Отложенный "остров" -->
<ProductReviews client:visible /> <!-- При появлении в viewport -->
</div>
Ключевые принципы:
- Минимум интерактивности: Только там, где действительно нужно
- Изоляция: Острова не зависят друг от друга
- Прогрессивность: Загрузка по мере необходимости
Преимущества:
- Экстремально быстрая загрузка
- Минимальный JavaScript
- Независимое обновление компонентов
- Отличные Core Web Vitals