Деплой React приложений

f

Когда локальная сборка перестаёт работать

Вы часами настраивали React-приложение: конфиги Webpack, thrее-shaking, code-splitting. Локально всё летает — 90 баллов Lighthouse, мгновенный HMR. Но как только вы заливаете build-папку на хостинг, страница висит, билд весит 12 МБ, консоль кричит о консолидэйшн-ошибках. Знакомо?

Разница между npm run build и тем, что попадает на сервер, колоссальна. Вы сталкиваетесь с абсолютными путями, неправильной обработкой SPA-маршрутизации (история без хеша) и, что критично, отсутствием кэширования статики. Браузер запрашивает /about, nginx возвращает 404, потому что он не знает, что все пути должен вести в index.html.

Именно здесь кроется главная ловушка для новичка: забыть настроить fallback. Без него лендинг откроется, а внутренние страницы — нет. Вы теряете клиентов, а пользователи видят белый экран и сообщение 'Not Found'.

Стандартный CRA против настроенного Vite: что выбрать для деплоя

Create React App (CRA) остаётся популярным стартером, но его деплой-выхлоп далёк от идеала. CRA по умолчанию генерирует bundle с core-js и polyfillami, увеличивая размер на 40–60 КБ. Для продакшена это непозволительная роскошь. Vite, напротив, использует esbuild для сборки и предлагает нативный ESM — бандл на 30% легче, а сам билд выполняется за 2–3 секунды вместо 15–20 у CRA.

При деплое React-приложения на Vite вы получаете не просто файлы, а оптимизированную структуру: dist/assets/ с хэшированными именами. Это автоматически решает проблему инвалидации кэша: как только меняется содержимое файла, меняется его хэш, и браузер подхватывает новую версию. Никакой ручной версии или параметров ?v=1.

Но есть нюанс: Vite по умолчанию генерирует относительные пути (./assets/index-abc.js). Если ваш хостинг использует поддиректорию (например, /app/), вручную добавьте base: '/app/' в vite.config. Иначе все ссылки развалятся на 404.

SSR и Pre-Rendering: когда клиентский деплой недостаточен

Чистый SPA (Single Page Application) отлично работает, когда SEO не критично. Но для каталога товаров, блога или коммерческого сайта без SSR-рендеринга не обойтись. Статические HTML-разметки из React-компонентов не хватает для поисковиков, которые почти не исполняют JavaScript. Результат — нулевая индексация страниц с контентом.

Вы решаете эту проблему двумя способами: либо полный серверный рендеринг на Node.js (Next.js, Remix), либо статическая генерация (Gatsby, Astro). Для деплоя React-приложения с SSR потребуется сервер, который умеет выполнять Node.js: VPS, облачные функции (Cloud Functions) или серверные контейнеры (Docker + Kubernetes). Статическая генерация проще: вы генерируете HTML на этапе сборки и деплоите готовые статические файлы на любой CDN или файловый хостинг.

В случае со статической генерацией используйте react-snapshot или react-static: они создают HTML-страницы для каждого роута. Предварительно настройте react-router-dom на BrowserRouter, а не на HashRouter, иначе неизбежны ошибки 404 при прямом переходе.

Пошаговая инструкция: деплой на Netlify с Git CI/CD

Netlify — один из самых простых вариантов для деплоя React-приложений. Вы подключаете репозиторий, указываете команду сборки (npm run build) и папку publish (build для CRA или dist для Vite). Вы настраиваете файл netlify.toml с правилом перезаписи для SPA:

[[redirects]]
from = "/*"
to = "/index.html"
status = 200

Без этой записи все пути, кроме корневого, вернут 404. После деплоя Netlify автоматически создаёт CDN-распространение, управляет SSL-сертификатами и делает каждый пуш в main новой версией. Вы получаете дашборд с информацией о бандле: время сборки, размер, загруженность.

Для production-деплоя на личный сервер используйте Nginx. Настройка виртуального хоста включает три ключевых директивы: root /var/www/your-app/build; try_files $uri $uri/ /index.html; настройка кэширования для /assets/ на год. Пример:

location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}

После рестарта nginx проверьте через curl -I /assets/main-abc123.js — в заголовках должна появиться дата Expires через год.

Оптимизация билда перед деплоем: что убрать, что добавить

Перед тем как запускать команду npm run build, проведите ревизию зависимостей. DevDependencies (eslint, prettier, typescript) не должны попадать в production. В webpack-конфиге установите mode: 'production' — это автоматически включает минификацию TerserWebpackPlugin и удалит console.log. Для Vite просто выполните vite build.

Далее — разделение кода (code splitting). Используйте React.lazy() для каждой страницы: const About = React.lazy(() => import('./pages/About')). Так начальный бандл будет весить не 2 МБ, а 200 КБ, а остальной код загрузится по требованию. На production оцениваете разницу через DevTools → Network — количество запросов возрастёт, но общий размер уменьшится.

Финальный этап — tree-shaking. Убедитесь, что библиотеки (moment.js, lodash) импортируются точечно: import { format } from 'date-fns' вместо import moment from 'moment'. Разница может достигать 200 КБ в бандле. Проверяйте размер через source-map-explorer.

Деплой на VPS с Docker: изолированный контейнер

Для полного контроля над средой — VPS (Virtual Private Server). Вы поднимаете Docker-контейнер с Nginx внутри. Создаёте Dockerfile в корне проекта:

FROM node:18-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:stable-alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Такой подход гарантирует идентичность сред: локальной и продакшена. Вы избегаете проблем с версиями Node, путями к бинарникам и пакетами системы. Кроме того, Docker-образ легко масштабировать через docker-compose или Kubernetes — добавьте балансировщик, и ваше приложение готово к 10 000 RPS.

Не забудьте настроить мониторинг: прикрепите к контейнеру логи в stdout (ACCESS_LOG /dev/stdout в nginx.conf), чтобы они отправлялись через Docker в централизованную систему (Azure Logs, AWS CloudWatch). Иначе вы не увидите ошибок и клиентских жалоб.

CI/CD на GitHub Actions: автоматический деплой при каждом пуше

Ручной деплой — источник ошибок: вы забыли запустить build, удалили нужный файл, залили тестовый код в production. CI/CD (Continuous Integration / Continuous Deployment) решает это автоматизацией. Создайте в репозитории файл .github/workflows/deploy.yml:

name: Deploy React App
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run build
- name: Deploy to Server
uses: easingthemes/ssh-deploy@v2
with:
SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
SOURCE: "build/"
REMOTE_HOST: ${{ secrets.HOST }}
REMOTE_USER: ${{ secrets.USER }}
TARGET: "/var/www/your-app"

После каждого пуша в main GitHub выполнит сборку, а затем по SSH скопирует build-папку на сервер. Вы следите за статусом в разделе Actions— если сборка зелёная, приложение обновлено. Используйте GitHub Secrets для хранения SSH-ключа (не в репозитории).

Добавьте авто-тесты перед сборкой: запускайте npm test -- --coverage. Если тесты завалились, деплой автоматически прервётся. Это спасёт от выкатывания сломанного UI.

Безопасность деплоя: утечка API-ключей и переменные окружения

Самая распространённая проблема — случайное размещение API-ключей в бандле. Если вы добавили const API_KEY = 'pk_test_...' в компонент React, этот ключ попадёт в JS-файлы, которые видит каждый пользователь через DevTools. Злоумышленники украдут ключи, на VM зальют миллионы запросов — получите счёт на $10 000 от Stripe.

Решение: переменные окружения (env vars). В React используйте REACT_APP_ префикс для CRA, для Vite — VITE_. Фреймворки подставляют их на этапе сборки: const baseURL = process.env.REACT_APP_API_URL. В production они должны быть недоступны для просмотра — если нужен секретный ключ для сервера, используйте серверные env (.env.production на сервере) и не включайте их в бандл.

Дополнительно: используйте .gitignore для исключения файлов .env с секретами. Не добавляйте их в репозиторий, иначе история Git сохранит ключи навсегда. Для CI/CD используйте зашифрованные секреты (GitHub, GitLab).

Что вы получите от изучения деплоя React-приложений

После прохождения этого руководства вы будете уверенно управлять полным циклом выкладки: от настройки билда до мониторинга живого приложения. Вы перестанете бояться production-окружения и сможете с нуля поднять React-приложение на VPS, Netlify или Docker за 10–15 минут.

Навыки деплоя прямо влияют на зарплату: middle-разработчик, который умеет настраивать CI/CD и управлять окружением, стоит на 20–30% дороже того, кто умеет только писать React-компоненты. Кроме того, вы сэкономите команде часы ручного переноса сборок и нервные поиски ошибок билда.

Практикуйтесь: возьмите простое приложение с тремя страницами, реализуйте все описанные способы деплоя, настройте GitHub Actions. После этого вы сможете смело указывать в резюме 'деплой React приложений с CI/CD и SSR'.

Добавлено: 23.04.2026