Фронтенд
Эта страница описывает, как подготовить фронтенд-приложение к деплою. Инструкции не привязаны к конкретному фреймворку — подойдёт любой инструмент, генерирующий статические файлы (React, Vue, Angular, Svelte, plain HTML и т.д.).
Принцип работы
Фронтенд в нашей инфраструктуре — это набор статических файлов (HTML, CSS, JS), которые раздаёт nginx из Docker-контейнера. Процесс:
- Сборка — фреймворк компилирует исходники в папку
dist/(или аналогичную). - Docker-образ — статика копируется в nginx-контейнер.
- Nomad — запускает контейнер и регистрирует его в Traefik.
- Traefik — терминирует TLS и маршрутизирует трафик.
Требования к фронтенду
| Требование | Описание |
|---|---|
| Статическая сборка | Приложение должно собираться в набор статических файлов (npm run build → dist/) |
| SPA-роутинг | Если используется клиентский роутинг, nginx должен отдавать index.html для всех путей |
| Health-эндпоинт | Настраивается в nginx.conf — Nomad проверяет /health |
Dockerfile
Фронтенд использует двухэтапную сборку: сначала собираем статику, затем копируем в nginx.
# ---- Сборка ----
FROM node:20-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
# ---- Раздача ----
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]TIP
Если ваш фреймворк использует другую выходную папку (например, build/ вместо dist/), измените путь в строке COPY --from=build.
nginx.conf
Конфигурация nginx для раздачи SPA с gzip-сжатием, кэшированием и health-эндпоинтом:
worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
# ---- Gzip ----
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_min_length 256;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# ---- Health-эндпоинт ----
location /health {
access_log off;
return 200 'ok';
add_header Content-Type text/plain;
}
# ---- Хэшированные ассеты — долгое кэширование ----
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# ---- index.html — без кэша ----
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
add_header Expires "0";
}
# ---- SPA fallback ----
location / {
try_files $uri $uri/ /index.html;
}
}
}WARNING
SPA fallback (try_files $uri $uri/ /index.html) обязателен. Без него обновление страницы на клиентском маршруте вроде /dashboard/settings вернёт 404.
Переменные окружения при сборке
Многие фреймворки поддерживают переменные окружения, которые подставляются на этапе сборки (build time). Например:
- Vite: переменные с префиксом
VITE_ - Create React App: переменные с префиксом
REACT_APP_ - Next.js: переменные с префиксом
NEXT_PUBLIC_
Передавайте их через BUILD_ARGS в CI:
BUILD_ARGS: "--build-arg VITE_API_URL=https://api.example.com"WARNING
Переменные окружения вкомпилируются в статику на этапе сборки. После создания Docker-образа их изменить нельзя. Если нужна динамическая конфигурация, используйте файл config.json, который генерируется при старте контейнера.
Структура проекта
Рекомендуемая структура репозитория для фронтенда:
my-service-frontend/
├── src/ # Исходный код приложения
├── public/ # Статические файлы
├── index.html
├── package.json
├── nginx.conf # Конфигурация nginx
├── Dockerfile
├── .gitlab-ci.yml
└── deploy/
├── my-service.nomad.hcl
├── dev.vars.hcl
├── stage.vars.hcl
└── prod.vars.hclЛокальная разработка
# Установите зависимости
npm install
# Запустите dev-сервер
npm run dev
# Соберите для продакшена
npm run buildСледующие шаги
- Создайте файлы деплоя — Dockerfile, nginx.conf, Nomad job.
- Пройдите чек-лист запуска перед выводом в продакшен.