Что такое серверный рендеринг (SSR) и как он реализован в Next.js?
Серверный рендеринг (Server-Side Rendering, SSR) — это подход, при котором HTML-страница генерируется на сервере и отправляется клиенту уже в готовом виде. Это отличается от классического SPA (Single Page Application), где HTML создаётся на стороне клиента после загрузки JavaScript-кода. SSR позволяет ускорить первую отрисовку страницы, улучшить SEO и сделать приложение доступным даже при медленном соединении.
Как работает SSR:
-
Пользователь отправляет HTTP-запрос (например, открывает страницу в браузере).
-
Сервер обрабатывает запрос, собирает данные, рендерит React-компоненты в HTML-строку.
-
Эта HTML-страница отправляется клиенту.
-
После загрузки клиентский JavaScript "гидратирует" страницу — прикрепляет обработчики событий к уже отрендеренной разметке.
-
Приложение становится интерактивным.
Преимущества SSR:
-
Быстрый Time to First Byte (TTFB): пользователь быстрее видит контент.
-
Улучшенная SEO: поисковые боты получают полноценный HTML с контентом, а не пустой div и JS-бандл.
-
Поддержка предварительного рендеринга: можно сгенерировать HTML на основе данных из API, cookies и т.д.
Next.js и SSR:
Next.js — фреймворк поверх React, который предоставляет встроенную поддержку SSR, наряду с другими стратегиями рендеринга (SSG, ISR, CSR). Он позволяет создавать страницы, которые рендерятся на сервере при каждом запросе с помощью специальных функций.
SSR в Next.js реализуется с помощью getServerSideProps
Это функция, которую можно экспортировать из страницы (pages/*.tsx). Она вызывается на сервере при каждом запросе и возвращает props, которые передаются компоненту страницы.
Пример:
// pages/profile.tsx
import React from 'react';
type Props = {
user: { id: number; name: string };
};
export const getServerSideProps = async () => {
const res = await fetch('https://api.example.com/user');
const user = await res.json();
return { props: { user } };
};
const ProfilePage = ({ user }: Props) => {
return (
<div>
<h1>Hello, {user.name}</h1>
</div>
);
};
export default ProfilePage;
-
getServerSideProps выполняется на Node.js-сервере.
-
Он может получать context, где есть req, res, query-параметры, cookies и т.д.
-
Используется, когда нужно всегда получать свежие данные.
Сравнение SSR с другими подходами в Next.js:
Подход | Когда выполняется | Пример функции | Где генерируется HTML |
---|---|---|---|
SSR | На каждый запрос | getServerSideProps | Сервер |
--- | --- | --- | --- |
SSG (Static Gen.) | Во время билда | getStaticProps | Сервер (на build time) |
--- | --- | --- | --- |
ISR (Revalidate) | По расписанию | getStaticProps + revalidate | Сервер |
--- | --- | --- | --- |
CSR | На клиенте | useEffect, fetch в компоненте | Браузер |
--- | --- | --- | --- |
Типичный use-case SSR:
-
Страницы, зависимые от пользовательских данных, авторизации (cookie, токены).
-
Динамическое содержимое, где данные часто меняются.
-
SEO-важные страницы с персонализированным контентом.
Особенности SSR в Next.js:
1. Доступ к req и res:
В getServerSideProps доступен context.req и context.res. Это позволяет:
-
читать куки, заголовки,
-
перенаправлять (redirect),
-
делать условную отрисовку.
Пример с редиректом:
export const getServerSideProps = async (context) => {
const { req } = context;
const isAuthenticated = Boolean(req.cookies.token);
if (!isAuthenticated) {
return {
redirect: {
destination: '/login',
permanent: false
}
};
}
return { props: {} };
};
2. SSR + API-запросы
Ты можешь использовать любые fetch-запросы на сервере:
-
К REST API
-
К базам данных напрямую (например, через Prisma, MongoDB, Supabase и т.п.)
export const getServerSideProps = async () => {
const res = await fetch('http://localhost:3000/api/news');
const data = await res.json();
return { props: { data } };
};
3. SSR и производительность
-
SSR требует больше ресурсов на сервере, т.к. каждый запрос рендерит страницу.
-
Можно использовать CDN/Edge Functions/Cache-Control для балансировки нагрузки.
-
Next.js поддерживает кеширование, etag, Cache-Control в SSR-ответах.
Гидратация (Hydration)
После того как SSR-страница загружена в браузер, React "гидратирует" её:
-
связывает уже отрендеренный HTML с виртуальным DOM,
-
добавляет обработчики событий,
-
позволяет React-приложению стать интерактивным.
SSR в Next.js 13+ (App Router)
С переходом на App Router и серверные компоненты SSR стало ещё мощнее и гибче.
Особенности:
-
По умолчанию app/ папка использует серверные компоненты (.tsx компоненты рендерятся на сервере).
-
Асинхронные серверные компоненты (async function Page() {}) позволяют делать fetch прямо в JSX.
-
SSR встроен без необходимости явно использовать getServerSideProps.
Пример с App Router:
// app/profile/page.tsx
async function getUser() {
const res = await fetch('https://api.example.com/user', { cache: 'no-store' });
return res.json();
}
export default async function ProfilePage() {
const user = await getUser();
return <div>Hello, {user.name}</div>;
}
Инструменты и дополнения:
-
Middleware: позволяет обрабатывать запросы до SSR (например, аутентификацию).
-
NextAuth.js: для SSR-авторизации и сессий.
-
@next/font: для оптимизации шрифтов на сервере.
-
next/cache: для управления кешем данных.
SSR в сочетании с CDN и Edge Functions:
Next.js может запускать SSR не только на основном сервере, но и ближе к пользователю — на edge-функциях (например, Vercel Edge Functions). Это снижает задержки и ускоряет доставку страниц.
export const config = {
runtime: 'edge',
};
Next.js предоставляет высокоуровневый API для реализации SSR с минимумом ручной настройки и с глубокими возможностями кастомизации.