Перейти к содержимому

13. React-приложение в Docker

React-приложение требует двух этапов: сборка статических файлов (требует Node.js, npm, все dev-зависимости) и раздача статики (достаточно легковесного nginx). Multi-stage build идеально подходит для этого случая.

React SPA (Single Page Application) компилируется в набор статических HTML, CSS и JS файлов. Для их раздачи в продакшене использует nginx — высокопроизводительный веб-сервер, образ которого всего ~25 MB.

# ─── Этап 1: Сборка ────────────────────────────────
FROM node:20-alpine AS build
WORKDIR /app
# Сначала зависимости (кеш)
COPY package*.json ./
RUN npm ci
# Потом код
COPY . .
# Аргумент сборки для API URL
ARG REACT_APP_API_URL=https://api.example.com
ENV REACT_APP_API_URL=$REACT_APP_API_URL
RUN npm run build
# Результат: /app/build
# ─── Этап 2: Nginx ─────────────────────────────────
FROM nginx:1.25-alpine AS production
# Скопировать собранное приложение
COPY --from=build /app/build /usr/share/nginx/html
# Кастомная конфигурация nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Nginx работает от непривилегированного пользователя
EXPOSE 80
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost/health || exit 1
CMD ["nginx", "-g", "daemon off;"]

Если приложение использует React Router (client-side routing), nginx должен перенаправлять все запросы на index.html:

nginx.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Сжатие
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
# Кеширование статики
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Роутинг SPA — все пути на index.html
location / {
try_files $uri $uri/ /index.html;
}
# Health check endpoint
location /health {
return 200 "healthy\n";
add_header Content-Type text/plain;
}
}
node_modules/
build/
.git/
.gitignore
.env
.env.local
.env.*.local
*.log
npm-debug.log*
README.md
.DS_Store
Dockerfile*
docker-compose*

React встраивает переменные окружения на этапе сборки (build time), а не во время выполнения. Переменные с префиксом REACT_APP_ попадают в бандл.

# Передача API URL при сборке
ARG REACT_APP_API_URL
ARG REACT_APP_VERSION
ENV REACT_APP_API_URL=${REACT_APP_API_URL:-http://localhost:3001}
ENV REACT_APP_VERSION=${REACT_APP_VERSION:-dev}
RUN npm run build
Окно терминала
# Сборка с конкретными переменными
docker build \
--build-arg REACT_APP_API_URL=https://api.prod.com \
--build-arg REACT_APP_VERSION=1.2.3 \
-t myapp:prod .
docker-compose.yml
services:
frontend-dev:
build:
context: .
dockerfile: Dockerfile.dev # с hot reload
ports:
- "3000:3000"
volumes:
- .:/app
- /app/node_modules
environment:
- REACT_APP_API_URL=http://localhost:3001
frontend-prod:
build:
context: .
target: production
args:
REACT_APP_API_URL: https://api.example.com
ports:
- "80:80"