Практическое руководство по созданию, тестированию и деплойю Server Components в React 19 с примерами кода и типичными ошибками. Время выполнения всех шагов: примерно 2–3 часа в среде разработчика с Node 20 и Next.js 14.
Что вы изучите
Как устроены React Server Components (RSC) в React 19 (релиз 2026) и зачем они нужны.
Создание базового Server Component и запуск в Next.js 14 (релиз 2025).
Передача данных с сервера в RSC: синхронно и асинхронно, примеры fetch с кэшированием.
Организация client boundary и взаимодействие client и server компонентов.
Тестирование Server Components и подготовка Docker-образа для деплоя.
Список типичных ошибок и способы их фиксить в 2025–2026 среде.
Требования
Node.js 20.x (LTS, релиз 2023) — рекомендуется для сборки и запуска; минимум Node 18.
React 19 (релиз 2026) — поддержка Server Components на уровне фреймворка.
Next.js 14 (релиз 2025) — серверный рендеринг и маршрутизация с поддержкой RSC.
ОЗУ: минимум 2 ГБ для локальной разработки, 1 CPU 2 vCPU.
Свободное место: ~300 МБ для проекта, Docker-образ на базе Node 20-slim ~90–140 МБ.
Порты: по умолчанию Next.js dev 3000, в Docker используйте 3000:3000.
Как работают server components?
0
Статья была полезной?
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…
Server Components в React 19 (релиз 2026) разделяют логику: часть дерева можно рендерить на сервере без передачи JavaScript-кода на клиент. Это сокращает размер бандла и позволяет выполнять операции с данными (запросы к базе, чтение файлов) непосредственно на сервере. Server Components могут быть асинхронными и возвращают готовый HTML-деревянный фрагмент или специальный поток для hydration. Client Components нужны для интерактивности — они загружаются и инициализируются в браузере через client boundary.
Шаг 1: базовый компонент
Цель: создать минимальный Server Component в Next.js 14 и запустить dev-сервер. Ожидаемое время: 10–20 минут.
Команда: создать проект и запустить dev-сервер.
npx create-next-app@14 my-rsc-app --experimental --use-pnpm
cd my-rsc-app
# установить React 19 (если create-next-app не подтянул автоматически)
pnpm add react@19 react-dom@19
pnpm dev
Пояснение: флаг --experimental может понадобиться для старых шаблонов; Next.js 14 уже адаптирован под React 19. Команда запускает dev-сервер на порту 3000. Время выполнения установки: 30–90 с в зависимости от сети.
Ожидаемый вывод (успех):
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info - Using React 19 (release 2026)
Фикс: Обновите Node.js до версии >=18; рекомендую Node 20 (LTS, 2023). Установка через nvm:
nvm install 20
nvm use 20
Шаг 2: передача данных
Цель: сделать Server Component, который асинхронно получает данные и рендерит их на сервере. Ожидаемое время: 20–30 минут.
Файлы: создайте файл app/components/Users.server.jsx (или /src/app/... по структуре).
import React from 'react'
export default async function Users() {
// fetch с server-side: можно обращаться к внутренним API или БД
const res = await fetch('https://jsonplaceholder.typicode.com/users', { cache: 'no-store' })
const users = await res.json()
return (
{users.slice(0,5).map(u => (
{u.name} — {u.email}
))}
)
}
Пояснение: Server Component может быть async; fetch выполняется на сервере, поэтому секреты и приватные ключи не попадают в бандл. Параметр cache: 'no-store' отключает кэширование, полезно для данных, которые меняются часто. Альтернативно используйте cache: 'force-cache' для агрессивного кэширования.
Фикс: используйте Node 18+ или добавьте полифилл fetch. В среде Next.js 14 fetch доступен, но при прямом запуске Node.js убедитесь, что версия Node поддерживает глобальный fetch или установите пакет node-fetch и используйте его: pnpm add node-fetch, затем import fetch from 'node-fetch'.
Шаг 3: client boundary
Цель: показать, как встроить интерактивный Client Component внутрь Server Component и управлять состоянием на клиенте. Ожидаемое время: 15–25 минут.
import Users from './Users.server'
import Counter from './Counter.client'
export default function Page() {
return (
<main>
<h1>Пользователи</h1>
<Counter start={10} /> {/* client boundary */}
<Users /> {/* server-rendered список */}
</main>
)
}
Пояснение: директива "use client" обязана быть первой строкой в файле Client Component. Встраивание client компонента создаёт boundary: HTML будет серверно-рендерен, а JavaScript для client-компонента загружается отдельно при гидратации. Это уменьшает общий размер JS, если большая часть UI не интерактивна.
Ожидаемый вывод: в браузере вы увидите интерактивные кнопки, счётчик реагирует мгновенно; Network покажет отдельный фрагмент JS для client-компонента (размер зависит от бандлера, обычно 5–30 КБ gz).
Типичная ошибка и её фикс:
Ошибка: Hydration mismatch: Expected node with text "10" but got "11"
Фикс: Избегайте использования нестабильных значений (Date.now, Math.random, auto-increment) в серверном HTML, либо передавайте начальное значение через пропсы и рассчитывайте его одинаково на сервере и клиенте. Для времени и динамических значений рендерьте placeholder на сервере и обновляйте на клиенте в useEffect.
Шаг 4: тестирование
Цель: сделать простые тесты для Server и Client компонентов. Время: 20–40 минут.
Пример теста для Server Component Users.server.test.jsx:
import { renderToString } from 'react-dom/server'
import Users from './Users.server'
it('renders user list server-side', async () => {
const html = await renderToString(Users())
expect(html).toContain('<ul>')
})
Пример теста для Client Component Counter.client.test.jsx:
import { render, fireEvent } from '@testing-library/react'
import Counter from './Counter.client'
it('increments counter on click', () => {
const { getByText } = render(<Counter start={1} />)
const plus = getByText('+')
fireEvent.click(plus)
expect(getByText('2')).toBeTruthy()
})
Фикс: настройте jsdom в конфигурации Vitest/Jest. В vitest.config.js добавьте test: { environment: 'jsdom' }. Для server-side тестов используйте react-dom/server и renderToString, чтобы не задействовать DOM.
Шаг 5: деплой
Цель: собрать Docker-образ и запустить приложение с React 19 и Next.js 14. Время: 20–40 минут (с учётом билда образа).
Dockerfile (Node 20-slim, образ ~120 МБ после сборки приложения):
FROM node:20-slim
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN pnpm install --frozen-lockfile --prod
COPY . .
RUN pnpm build
EXPOSE 3000
CMD ["pnpm", "start"]
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
Типичная ошибка и её фикс:
Ошибка: EADDRINUSE: address already in use 0.0.0.0:3000
Фикс: проверьте, не занят ли порт 3000 на хосте, используйте другой порт при запуске Docker: docker run -p 4000:3000 ..., или остановите процесс, который использует порт.
Когда использовать "use client"?
Директива "use client" применяется в файле компонента, чтобы явно пометить его как client-only. Используйте её, когда компонент требует состояния через хуки (useState, useEffect), доступ к DOM или обработку событий. Если компонент просто отображает данные и не использует браузерные API, оставляйте его server-side: это уменьшит бандл для клиента. Правило простое: пометь как client только те компоненты, которые действительно нуждаются в интерактивности. Это уменьшит объём JS и ускорит Time-to-Interactive. В React 19 (2026) рекомендуется минимизировать число client boundary: чем меньше интерактивных точек, тем меньше сетевых запросов и бандлов.
Какие ошибки частые?
Список распространённых проблем при работе с RSC и способы их устранения — обзор и практические рекомендации.
Почему появляется hydration mismatch?
Hydration mismatch возникает, когда HTML, сгенерированный на сервере, отличается от того, что ожидает клиент при гидратации. Частые причины: использование Date.now(), Math.random(), чтение локального состояния (localStorage) при серверном рендеринге, или рендеринг разного числа элементов (например, из асинхронных вызовов без одинаковых данных). Фиксы: вычисляйте динамические значения на клиенте в useEffect, передавайте одинаковые начальные значения через пропсы, или используйте placeholders на сервере, затем обновляйте на клиенте. В Next.js 14 и React 19 логируйте HTML на сервере и сравнивайте с клиентским DOM в DevTools для отладки.
Когда fetch работает на сервере, но падает локально?
Если запросы выполняются на дев-сервере Next.js, но падают при unit-тестах или при запуске «node server.js», вероятная причина — отсутствие глобального fetch в среде Node (< Node 18) или в тестовом рантайме. Решение: используйте Node 18+ (рекомендуется Node 20) или подключите полифилл node-fetch в окружениях, где fetch не определён. Для тестов настройте моки сетевых вызовов (msw) и используйте jsdom для клиентских тестов.
Чем вызвана ошибка "Client component used in a server-only context"?
Эта ошибка возникает, если вы импортируете client-компонент внутрь server-компонента без явной client boundary (например, забыли добавить "use client" в child-файл). Убедитесь, что клиентский файл содержит директиву и импортируется как JSX-элемент, а не как обычная функция, возвращающая DOM. Также проверьте, что сборщик (Next.js 14) корректно распознаёт расширения файлов и правила трансформации.
Где смотреть логи и как профилировать рендеринг на сервере?
Логи сервера доступны в консоли Next.js или в логах контейнера Docker. Для профилирования используйте встроенные инструменты: React DevTools (Server Profiler), а также профайлер Node.js (clinic, 0x) для определения горячих точек при fetch/DB-запросах. Измеряйте время рендеринга отдельных Server Components — добавьте простые метрики с process.hrtime() вокруг асинхронных операций и отправляйте их в логи. На production окружении включайте sampling логов, чтобы не перегружать систему.
Скриншот терминала: запуск Next.js dev-сервера с React 19
Скриншот браузера: Server Component рендерит список пользователей и client counter
React 19 (2026) позволяет экономить клиентский JS за счёт выполнения части UI на сервере.
Next.js 14 (2025) предоставляет готовую интеграцию RSC и маршрутизацию app-router.
Node 20 (LTS, 2023) рекомендуется для корректной работы fetch и сборки.
Полезные материалы на сайте: React, JavaScript — обзоры и практические руководства по фронтенд-инструментарю.
Частые вопросы
как Server Components влияют на размер клиентского бандла?
Server Components уменьшают клиентский бандл за счёт перемещения рендеринга неподвижных или «read-only» частей UI на сервер. Вместо передачи JavaScript для всего дерева клиент получает минимальные дельты и отдельные скрипты только для client boundaries. Практическое снижение зависит от приложения: в проектах с большой неинтерактивной частью биндинг может сократиться на 30–70%. В React 19 (2026) и Next.js 14 (2025) наблюдается заметное уменьшение Time-to-Interactive и First Contentful Paint при аккуратном разбиении на server/client компоненты.
что делать, если нужно использовать browser API внутри Server Component?
Server Components выполняются в среде сервера, поэтому нельзя напрямую использовать browser API (localStorage, window, document). Решение: вынесите логику, зависящую от браузера, в client-компонент, пометьте файл директивой "use client", и передавайте нужные данные через props или через API-запросы. Если нужно вычислить значение на клиенте после начальной загрузки, используйте useEffect в client-компоненте и обновляйте вид.
какой overhead у Server Components на стороне сервера?
Server Components добавляют нагрузку на сервер, потому что рендеринг происходит server-side. Overhead зависит от сложности рендеринга и количества асинхронных вызовов (DB, внешние API). На типичном облачном инстансе (2 vCPU, 4 ГБ RAM) одно простое приложение с RSC обслуживает десятки TPS без проблем; при увеличении трафика масштабируйте горизонтально. Рекомендуется кэшировать результаты (HTTP cache, CDN, edge) и минимизировать задержки внешних API, чтобы снизить время отклика серверной части.
сколько памяти занимает Docker-образ с Next.js 14 + React 19?
Базовый Docker-образ на Node 20-slim вместе с собранным Next.js-приложением обычно занимает 90–140 МБ, в зависимости от зависимостей и статики. При использовании full Node image (non-slim) размер может вырасти до 300–500 МБ. Для production рекомендуется multi-stage build и минимизация dev-зависимостей в финальном образе — это снизит время деплоя и стоимость хранения.
чем отличается использование RSC в edge vs origin?
При рендеринге на edge (edge functions, CDN) Server Components выигрывают в latency для геораспределённых пользователей: HTML формируется ближе к клиенту. Ограничение — среда edge часто менее функциональна (ограничение памяти, меньше нативных API, короткие таймауты). Origin-сервер предоставляет больше ресурсов и гибкости для доступа к БД и бэкэнду. Выбирайте edge для агрессивного caching и низкой latency, origin — для тяжёлых вычислений и прямого доступа к приватным ресурсам.
Комментарии (0)
Войдите или зарегистрируйтесь, чтобы оставить комментарий
Загрузка комментариев…