Skip to content

Фронтенд

Эта страница описывает, как подготовить фронтенд-приложение к деплою. Инструкции не привязаны к конкретному фреймворку — подойдёт любой инструмент, генерирующий статические файлы (React, Vue, Angular, Svelte, plain HTML и т.д.).

Принцип работы

Фронтенд в нашей инфраструктуре — это набор статических файлов (HTML, CSS, JS), которые раздаёт nginx из Docker-контейнера. Процесс:

  1. Сборка — фреймворк компилирует исходники в папку dist/ (или аналогичную).
  2. Docker-образ — статика копируется в nginx-контейнер.
  3. Nomad — запускает контейнер и регистрирует его в Traefik.
  4. Traefik — терминирует TLS и маршрутизирует трафик.

Требования к фронтенду

ТребованиеОписание
Статическая сборкаПриложение должно собираться в набор статических файлов (npm run builddist/)
SPA-роутингЕсли используется клиентский роутинг, nginx должен отдавать index.html для всех путей
Health-эндпоинтНастраивается в nginx.conf — Nomad проверяет /health

Dockerfile

Фронтенд использует двухэтапную сборку: сначала собираем статику, затем копируем в nginx.

dockerfile
# ---- Сборка ----
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-эндпоинтом:

nginx
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:

yaml
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

Локальная разработка

bash
# Установите зависимости
npm install

# Запустите dev-сервер
npm run dev

# Соберите для продакшена
npm run build

Следующие шаги

Документация по инфраструктуре