CSR, SSR, SSG: обзор подходов
CSR (Client-Side Rendering), SSR (Server-Side Rendering) и SSG (Static Site Generation) — три основных стратегии рендеринга веб-приложений, определяющие где и когда генерируется HTML.
Зачем нужно
Выбор стратегии рендеринга напрямую влияет на производительность, SEO и сложность проекта. CSR подходит для внутренних инструментов без SEO-требований; SSR нужен, когда важны и SEO, и динамический контент; SSG обеспечивает максимальную скорость для редко меняющихся страниц. Понимание разницы позволяет принимать осознанные архитектурные решения на этапе проектирования, а не переделывать их позже.
Где используется
- CSR: дашборды, CRM, SaaS-приложения за авторизацией (Trello, Notion)
- SSR: e-commerce, новостные сайты, публичные приложения с SEO (Next.js с getServerSideProps)
- SSG: блоги, документация, лендинги (Astro, Next.js static export, Gatsby)
- Гибрид: Next.js App Router позволяет использовать разные стратегии на разных маршрутах
Сравнение подходов
CSR (Client-Side Rendering)
──────────────────────────
Сервер → пустой HTML + bundle.js
Браузер → выполняет JS → строит DOM
SSR (Server-Side Rendering)
──────────────────────────
Запрос → сервер рендерит HTML с данными → отправляет браузеру
Браузер → показывает HTML → загружает JS → hydration
SSG (Static Site Generation)
────────────────────────────
npm run build → генерирует HTML-файлы → CDN
Браузер → получает готовый HTML мгновенно
Метрики сравнения
| Критерий | CSR | SSR | SSG |
|---|---|---|---|
| TTFB (Time to First Byte) | Быстрый | Медленнее (рендеринг на сервере) | Быстрый (CDN) |
| FCP (First Contentful Paint) | Медленный | Быстрый | Быстрый |
| SEO | Сложно | Нативно | Нативно |
| Динамические данные | Да | Да | Нет (нужен rebuild) |
| Масштабирование | Легко (статика) | Нужен сервер | Легко (CDN) |
| Сложность | Средняя | Высокая | Низкая |
Пример: CSR (React без SSR)
// Браузер получает пустую страницу, JS строит UI
function App() {
const [users, setUsers] = React.useState();
React.useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(setUsers);
}, );
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Пример: SSR (Next.js)
// pages/users.jsx — данные загружаются на сервере при каждом запросе
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/users');
const users = await res.json();
return { props: { users } };
}
export default function UsersPage({ users }) {
// HTML уже содержит список пользователей при первой отдаче
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Пример: SSG (Next.js)
// pages/blog/[slug].jsx — страницы генерируются при сборке
export async function getStaticPaths() {
const posts = await fetchAllPosts;
return {
paths: posts.map(p => ({ params: { slug: p.slug } })),
fallback: false,
};
}
export async function getStaticProps({ params }) {
const post = await fetchPost(params.slug);
return { props: { post } };
}
export default function BlogPost({ post }) {
return <article><h1>{post.title}</h1><p>{post.content}</p></article>;
}
Частые ошибки
- CSR для публичного сайта — Google всё лучше рендерит JS, но другие поисковики и социальные сети (og:tags) по-прежнему видят пустой HTML.
- SSR для статических данных — запускать сервер для страниц, которые меняются раз в месяц, — избыточно; SSG + ISR справится лучше.
- Забывают о hydration mismatch — при SSR HTML с сервера должен точно совпадать с тем, что React генерирует на клиенте; расхождения приводят к ошибкам.
Связанные темы
- _MOC SPA
- Что такое SPA
- SSR -- Server Side Rendering
- SSG -- Static Site Generation
- ISR -- Incremental Static Regeneration
- Next.js -- обзор