О чём эта статья и зачем её читать
Когда компания решает сделать сайт или веб-приложение, одним из первых встаёт вопрос: какую технологию использовать? В мире React (самой популярной библиотеки для создания сайтов) есть два основных подхода - SPA и SSR. За этими аббревиатурами стоят совершенно разные способы показать вам сайт. И от выбора зависит, насколько быстро сайт будет загружаться, увидят ли его поисковики и сколько будет стоить хостинг.
Давайте разберёмся в этом простым языком, без лишнего занудства. Даже если вы не программист - после этой статьи вы поймёте, что к чему, и сможете осознанно обсуждать это с разработчиками.
Аналогия: ресторан и конструктор
Представьте два ресторана.
В первом (это SSR - серверный рендеринг) повар готовит блюдо на кухне и приносит вам готовое. Вы открываете крышку - и сразу видите красивый стейк с гарниром. Можно сразу есть.
Во втором ресторане (это SPA - одностраничное приложение) вам приносят поднос с ингредиентами и инструкцию. Вы сами собираете блюдо за столом. Первый раз ждёте дольше (пока всё приготовите), но потом, если хотите добавку или изменить гарнир - всё происходит мгновенно, без ожидания кухни.
Оба подхода кормят вас. Но работают по-разному, и каждый лучше в своей ситуации.
Что такое SPA (одностраничное приложение)
SPA расшифровывается как Single Page Application - «одностраничное приложение». Это значит, что весь сайт - это технически одна HTML-страница. Когда вы первый раз заходите на такой сайт, браузер (программа, через которую вы смотрите сайты - Chrome, Safari, Firefox) скачивает весь код сайта целиком. После этого переходы между страницами происходят мгновенно - браузер просто перерисовывает содержимое, не обращаясь к серверу за новой страницей.
Как это выглядит для пользователя:
- Вы вводите адрес сайта в браузере
- Браузер получает почти пустую страницу (буквально белый экран на долю секунды)
- Скачивается JavaScript-код (программа, которая построит сайт)
- Код выполняется и рисует интерфейс - вы видите сайт
- Дальше всё работает молниеносно - клики, переходы, анимации
// Это упрощённый пример SPA-приложения
// Не пугайтесь кода - просто посмотрите на комментарии
// Подключаем нужные инструменты из React
import { lazy, Suspense } from 'react'
// Загружаем страницы "лениво" - только когда пользователь на них перейдёт
// Это экономит трафик: зачем скачивать страницу "О нас",
// если пользователь смотрит только главную?
const Home = lazy(() => import('./pages/Home'))
const Products = lazy(() => import('./pages/Products'))
const About = lazy(() => import('./pages/About'))
// Описываем маршруты - какой адрес какой странице соответствует
// "/" - главная страница
// "/products" - каталог товаров
// "/about" - страница "О нас"
const routes = [
{ path: '/', element: <Home /> },
{ path: '/products', element: <Products /> },
{ path: '/about', element: <About /> },
]
// Пока страница загружается - показываем надпись "Загрузка..."
// Это тот самый момент, когда пользователь видит пустой экран
function App() {
return (
<Suspense fallback={<div>Загрузка...</div>}>
<RouterProvider routes={routes} />
</Suspense>
)
}
Плюсы SPA:
- После первой загрузки всё работает очень быстро - страницы переключаются мгновенно
- Приятный пользовательский опыт - нет перезагрузок страницы
- Простой и дешёвый хостинг - это просто набор файлов, можно положить куда угодно
- Проще разрабатывать - меньше сложностей с сервером
Минусы SPA:
- Первая загрузка медленнее - нужно скачать весь код
- Поисковые роботы (Google, Яндекс) могут не увидеть содержимое - они получают пустую страницу
- Пока код не загрузится - пользователь видит белый экран
Что такое SSR (серверный рендеринг)
SSR расшифровывается как Server-Side Rendering - «рендеринг на стороне сервера». Сервер - это мощный компьютер, на котором живёт ваш сайт. При SSR этот компьютер сам формирует готовую страницу и отправляет её браузеру. Браузер получает уже готовый HTML (код страницы) с текстом, картинками и всем содержимым.
Как это выглядит для пользователя:
- Вы вводите адрес сайта
- Сервер формирует готовую страницу со всем содержимым
- Браузер получает готовый HTML и сразу показывает контент
- Параллельно загружается JavaScript, который делает страницу интерактивной (кнопки начинают работать)
Next.js - это самый популярный инструмент для создания сайтов с SSR. Он построен на React и добавляет серверный рендеринг «из коробки» (то есть без дополнительных настроек).
// Пример страницы на Next.js с серверным рендерингом
// Этот код выполняется на СЕРВЕРЕ, а не в браузере пользователя
// Функция для страницы товара
// params.id - это номер товара из адресной строки
// Например, для адреса /products/42 params.id будет "42"
export default async function ProductPage({ params }) {
// Сервер сам запрашивает данные о товаре из базы данных
// Пользователь этого не видит - всё происходит на сервере
const product = await getProductFromDatabase(params.id)
// Сервер формирует готовый HTML и отправляет его пользователю
// Пользователь сразу видит название и описание товара
return (
<div>
<h1>{product.name}</h1>
<p>Цена: {product.price} руб.</p>
<p>{product.description}</p>
</div>
)
}
// Метаданные для поисковиков - тоже генерируются на сервере
// Это то, что Google показывает в результатах поиска
export async function generateMetadata({ params }) {
const product = await getProductFromDatabase(params.id)
return {
// Заголовок страницы - появится во вкладке браузера и в Google
title: product.name + ' - купить в нашем магазине',
// Описание - Google покажет его под заголовком
description: product.shortDescription,
}
}
А ещё есть SSG и ISR
Помимо SPA и SSR существуют ещё два подхода, и они тоже стоят внимания:
SSG (Static Site Generation) - статическая генерация. Все страницы создаются заранее, на этапе сборки сайта. Это как напечатать каталог в типографии - все страницы готовы заранее, их остаётся только раздать. Идеально для блогов, документации и лендингов, где содержимое меняется редко.
ISR (Incremental Static Regeneration) - инкрементальная статическая регенерация. Звучит сложно, но идея простая: страницы генерируются статически (как в SSG), но автоматически обновляются через заданный интервал. Это как каталог, который сам перепечатывает устаревшие страницы. Вы получаете скорость статики и актуальность данных.
// Пример ISR в Next.js
// Эта страница будет обновляться каждые 60 секунд
// revalidate = 60 означает:
// "Покажи кэшированную версию, но через 60 секунд обнови её"
export const revalidate = 60
export default async function PricePage() {
// Цены загружаются из базы данных
const prices = await getPrices()
return (
<div>
<h1>Наши цены</h1>
<p>Лендинг: от {prices.landing} руб.</p>
<p>Интернет-магазин: от {prices.shop} руб.</p>
<p>Обновлено: {new Date().toLocaleString()}</p>
</div>
)
}
// Первый посетитель получит свежую страницу
// Следующие 60 секунд все получают кэшированную (мгновенную) версию
// Через 60 секунд страница обновится в фоне
Когда серверный рендеринг реально нужен
SSR - это не «всегда лучше». Это инструмент для конкретных задач. Вот когда он действительно необходим:
1. Когда важно, чтобы сайт находили в Google и Яндексе
Поисковые роботы - это программы, которые обходят интернет и собирают информацию о сайтах. Они заходят на вашу страницу и смотрят, что там написано. Проблема в том, что SPA-сайт при первом заходе показывает пустую страницу. Да, через секунду JavaScript нарисует всё содержимое, но робот может этого не дождаться.
Google научился ждать и выполнять JavaScript, но делает это с задержкой (иногда несколько дней). Если у вас интернет-магазин с тысячами товаров - каждый день задержки индексации это потерянные клиенты. SSR решает эту проблему: робот получает готовую страницу со всем содержимым сразу.
2. Когда скорость загрузки критична для бизнеса
Исследования показывают: каждая лишняя секунда загрузки уменьшает конверсию на 7%. Для интернет-магазина с оборотом 10 млн рублей в месяц одна секунда задержки - это 700 000 рублей потерь. SSR даёт выигрыш в 0.5-1.5 секунды по сравнению с SPA, потому что пользователь видит контент раньше.
3. Когда контент зависит от пользователя
Если нужно показать разные цены для разных регионов, персональные рекомендации или результаты A/B-тестов с первого кадра - SSR позволяет сформировать нужную версию страницы на сервере, до того как пользователь её увидит.
Когда SPA - лучший выбор
А вот ситуации, когда SSR не нужен и только добавляет сложности:
1. Админ-панели и внутренние инструменты
Админка интернет-магазина, CRM-система, корпоративный портал - всё это закрыто за логином. Поисковики туда не зайдут, а сотрудники готовы подождать пару секунд первой загрузки. Зато потом они работают в быстром интерфейсе, который не перезагружается при каждом действии.
2. Приложения, где пользователь проводит много времени
Если человек работает в вашем приложении часами (бухгалтерская программа, редактор документов, система управления проектами) - первая загрузка не так важна. Важно, чтобы дальше всё летало. SPA здесь идеален.
3. Прототипы и MVP
Когда нужно быстро проверить бизнес-идею, SPA на Vite (быстрый инструмент для сборки сайтов) разворачивается за минуты. Добавлять серверный рендеринг на этом этапе - трата времени. Если идея выстрелит - перейдёте на Next.js позже.
Что такое гидрация и почему с ней бывают проблемы
Гидрация (от слова «hydrate» - наполнять водой) - это процесс, при котором статичная HTML-страница «оживает». Представьте музей восковых фигур. SSR создаёт красивые фигуры (HTML), а гидрация превращает их в живых людей (добавляет интерактивность - кнопки начинают нажиматься, формы начинают отправляться).
Проблема возникает, когда то, что сервер нарисовал, отличается от того, что браузер пытается нарисовать. Это как если бы восковая фигура была блондинкой, а «живая версия» - брюнеткой. React видит несовпадение и ругается.
// Пример проблемы с гидрацией
// ПЛОХО: сервер и браузер покажут разное время
// На сервере сейчас 10:00 (серверное время)
// У пользователя в Москве - 15:00
// React видит несовпадение и выдаёт ошибку
function Clock() {
return <p>Сейчас {new Date().toLocaleTimeString()}</p>
}
// ХОРОШО: показываем время только после загрузки в браузере
function Clock() {
// Сначала показываем пустое значение (одинаково на сервере и клиенте)
const [time, setTime] = useState('')
// useEffect запускается ТОЛЬКО в браузере, после загрузки
// Сервер этот код не выполняет
useEffect(() => {
setTime(new Date().toLocaleTimeString())
// Обновляем каждую секунду
const timer = setInterval(() => {
setTime(new Date().toLocaleTimeString())
}, 1000)
return () => clearInterval(timer)
}, [])
return <p>{time ? `Сейчас ${time}` : 'Загружаем часы...'}</p>
}
Серверные и клиентские компоненты в Next.js
В современном Next.js (версия 13 и выше) появилось важное нововведение: компоненты бывают серверные и клиентские.
Серверный компонент - работает только на сервере. Может напрямую обращаться к базе данных, читать файлы на сервере. Его код не отправляется в браузер пользователя, что экономит трафик. Это как повар, который работает на кухне - вы видите только готовое блюдо.
Клиентский компонент - работает в браузере. Нужен для всего интерактивного: кнопки, формы, анимации, всё что реагирует на действия пользователя. Отмечается специальной строкой 'use client' в начале файла.
// Серверный компонент (по умолчанию в Next.js)
// Этот код НИКОГДА не попадёт в браузер пользователя
// Он выполняется на сервере и отправляет только готовый HTML
async function ProductList() {
// Можно напрямую обращаться к базе данных!
// В обычном SPA так нельзя - браузер не имеет доступа к базе
const products = await db.query('SELECT * FROM products')
return (
<ul>
{products.map(p => (
<li key={p.id}>{p.name} - {p.price} руб.</li>
))}
</ul>
)
}
// Клиентский компонент - работает в браузере
// Строка 'use client' говорит: "этот код нужен в браузере"
'use client'
function AddToCartButton({ productId }) {
// useState - хранит состояние (загружается кнопка или нет)
const [loading, setLoading] = useState(false)
// Эта функция выполнится, когда пользователь нажмёт кнопку
const handleClick = async () => {
setLoading(true) // Показываем что идёт загрузка
// Отправляем запрос на сервер - "добавь этот товар в корзину"
await fetch('/api/cart', {
method: 'POST',
body: JSON.stringify({ productId }),
})
setLoading(false) // Загрузка завершена
}
return (
<button onClick={handleClick}>
{loading ? 'Добавляем...' : 'В корзину'}
</button>
)
}
Сравнение скорости
Мы протестировали один и тот же сайт-каталог (50 товаров на главной, карточки с картинками) в разных режимах. Тестировали на медленном мобильном интернете (3G), потому что именно на слабом соединении разница видна лучше всего:
| Что измеряем | SPA (Vite) | SSR (Next.js) | SSG (Next.js) |
|---|---|---|---|
| Когда пользователь увидит первый контент | 3.2 сек | 1.4 сек | 0.8 сек |
| Когда загрузится главный элемент | 4.8 сек | 2.1 сек | 1.2 сек |
| Когда можно кликать по кнопкам | 5.1 сек | 3.8 сек | 2.5 сек |
| Размер скачиваемого кода | 285 КБ | 210 КБ | 180 КБ |
Как видите, SSR и SSG показывают контент в 2-3 раза быстрее. Но учтите: после первой загрузки SPA работает быстрее при навигации между страницами (нет обращений к серверу).
Разница в хостинге и стоимости
Это важный практический момент, который часто забывают:
SPA - это просто набор файлов (HTML, CSS, JavaScript). Их можно положить на любой хостинг, даже самый дешёвый. Стоимость: от 0 до 500 рублей в месяц. Никаких серверов, никаких процессов - просто файлы, которые отдаются посетителям.
Next.js с SSR - это полноценная серверная программа, которая должна работать 24/7. Нужен VPS (виртуальный сервер) или облачный хостинг. Стоимость: от 500 до 5000 рублей в месяц. Нужен мониторинг, нужно следить чтобы процесс не упал.
Как выбрать: простая шпаргалка
Ответьте на эти вопросы - и выбор станет очевидным:
- Сайт должен хорошо находиться в Google/Яндексе? Да - Next.js. Нет (внутренний инструмент) - SPA
- Контент одинаковый для всех? Да и меняется редко - SSG. Да но меняется часто - ISR. Разный для разных пользователей - SSR
- Это приложение за логином? Да - SPA
- Важна каждая десятая секунды загрузки? Да (e-commerce, медиа) - SSR/SSG. Нет - SPA
- Бюджет ограничен? SPA дешевле в хостинге. Next.js дороже но мощнее
Главная ошибка - выбирать технологию потому что она «модная». Next.js отлично подходит для контентных сайтов и интернет-магазинов. Vite+React - для приложений за логином. Это не конкуренты, это инструменты для разных задач.
Практический пример: когда мы выбираем Next.js для клиентов
Вот реальные сценарии из нашей практики:
Проект 1: Интернет-магазин одежды
Клиент пришёл с SPA-сайтом на React. Проблема: Google не индексировал страницы товаров, потому что они рендерились на клиенте. Трафик из поиска - 0. Мы перевели на Next.js с SSG (статической генерацией) для страниц товаров. Через 2 месяца органический трафик вырос на 400%.
Проект 2: Дашборд для аналитики
Клиент хотел "красивый дашборд для менеджеров". SEO не нужен (сайт за авторизацией), контент динамический (графики обновляются каждые 5 секунд). Мы оставили SPA на React + Vite - быстрее в разработке, дешевле в поддержке, и для этой задачи SSR не даёт никаких преимуществ.
Проект 3: Блог с высокой посещаемостью
Клиент - медиа-компания, 500+ статей, 100 000 посетителей в месяц. Выбрали Next.js с ISR (инкрементальной статической регенерацией): страницы статей генерируются один раз и кэшируются, обновляются каждые 60 секунд. Результат: время загрузки 0.3 секунды, нагрузка на сервер минимальная.
Советы по миграции: как перейти с SPA на Next.js
Если вы решили перевести существующий SPA на Next.js, вот пошаговый план:
// Шаг 1: Начните с маршрутизации
// В SPA маршруты обычно описаны в одном файле (react-router)
// В Next.js - файловая маршрутизация (каждый файл = маршрут)
// Было (React Router):
// src/App.tsx
// <Routes>
// <Route path="/" element={<Home />} />
// <Route path="/products" element={<Products />} />
// <Route path="/products/:id" element={<ProductDetail />} />
// </Routes>
// Стало (Next.js App Router):
// src/app/page.tsx - главная страница (/)
// src/app/products/page.tsx - список товаров (/products)
// src/app/products/[id]/page.tsx - страница товара (/products/123)
// Шаг 2: Определите, какие страницы нуждаются в SSR
// Не все! Только те, которым нужен SEO или быстрая первая загрузка
// Страницы для SSR/SSG (нужен SEO):
// - Главная, каталог, страницы товаров, блог, о компании
// Страницы для CSR (не нужен SEO):
// - Личный кабинет, корзина, оформление заказа, админ-панель
// Шаг 3: Разделите компоненты на серверные и клиентские
// По умолчанию в Next.js 15 все компоненты - серверные
// Добавьте 'use client' только там, где нужна интерактивность
// Серверный компонент (по умолчанию):
// Рендерится на сервере, не отправляет JavaScript клиенту
export default async function ProductPage({ params }) {
// Этот запрос к БД выполняется на сервере!
// Клиент НЕ видит строку подключения к базе данных
const product = await prisma.product.findUnique({
where: { id: params.id }
})
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
{/* AddToCartButton - клиентский компонент (интерактивный) */}
<AddToCartButton productId={product.id} />
</div>
)
}
// Клиентский компонент (с 'use client'):
// 'use client'
// import { useState } from 'react'
// export function AddToCartButton({ productId }) {
// const [added, setAdded] = useState(false)
// return <button onClick={() => { addToCart(productId); setAdded(true) }}>
// {added ? 'В корзине' : 'В корзину'}
// </button>
// }
Миграция не обязательно должна быть "всё или ничего". Вы можете переводить страницы постепенно: начните с тех, где SEO критичен (главная, каталог), а личный кабинет оставьте как SPA-компоненты с 'use client'.
Итого
SSR (серверный рендеринг) - это когда сервер готовит страницу целиком и отдаёт её браузеру готовой. Пользователь видит контент быстрее, поисковики видят всё содержимое. SPA (одностраничное приложение) - это когда браузер сам строит страницу из скачанного кода. Первая загрузка медленнее, но потом всё работает молниеносно.
Для бизнеса важно понимать: если ваш сайт должны находить клиенты через поиск и скорость загрузки влияет на продажи - выбирайте SSR (Next.js). Если вы делаете внутренний инструмент или приложение для постоянных пользователей - SPA будет проще и дешевле.
Не знаете, что подойдёт именно вам? Напишите нам - поможем разобраться и выбрать оптимальное решение для вашего проекта.