Деплой React и Vite: nginx, маршруты SPA и кэш

Как собрать React-приложение, настроить nginx для вложенных маршрутов, разделить кэш HTML и assets и разместить сайт в Inquir Compute.

Деплой React и Vite: nginx, маршруты SPA и кэш

После npm run build React-приложение на Vite становится набором HTML, JavaScript и CSS. Для выдачи этих файлов не нужен постоянно работающий Vite dev server. Ниже — контейнер с nginx для Inquir Compute, который корректно открывает вложенные маршруты SPA.

Разделите сборку и выдачу файлов

Проверьте, что локально выполняются npm ci и npm run build, а результат появляется в dist. Если проект использует другой build.outDir, измените путь копирования в Dockerfile. Команда vite preview предназначена для проверки сборки локально, а не для рабочего сервера — см. руководство Vite.

FROM node:22-bookworm-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginxinc/nginx-unprivileged:stable-alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist/ /usr/share/nginx/html/
EXPOSE 8080

Для воспроизводимых рабочих релизов зафиксируйте проверенные версии или digest образов. В .dockerignore исключите .env, node_modules, .git и локальный dist, чтобы сборка не зависела от файлов на ноутбуке.

Настройте маршруты и кэш

Создайте nginx.conf:

server {
    listen 8080;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;
    absolute_redirect off;

    location = /healthz {
        default_type text/plain;
        return 200 "ok\n";
    }
    location /assets/ {
        add_header Cache-Control "public, max-age=31536000, immutable";
        try_files $uri =404;
    }
    location / {
        add_header Cache-Control "no-cache";
        try_files $uri $uri/ /index.html;
    }
}

Fallback на index.html нужен для прямого перехода на /settings/profile, который обрабатывает React Router. Но отсутствующий JavaScript-файл в /assets/ должен возвращать 404: HTML вместо JavaScript приводит к ошибкам MIME или Unexpected token '<'.

Годовой кэш подходит только файлам с хэшем содержимого в имени. HTML должен перепроверяться, чтобы браузер получил ссылки на новую сборку. Не применяйте immutable ко всему сайту.

Разместите сайт в Inquir

После настройки CLI выполните из каталога проекта:

inquir apps create react-site --ingress public --port 8080 --health-path /healthz
inquir apps deploy react-site --promote
inquir apps status react-site

На адресе из status проверьте главную, прямое открытие вложенного маршрута и обновление страницы на нём. Путь должен существовать в вашем роутере; nginx не создаёт отсутствующие React-страницы. Отдельно запросите несуществующий /assets/missing.js — ожидается 404.

Переменные Vite не являются секретами

Значения VITE_*, используемые клиентским кодом, включаются в сборку и видны посетителю. В них допустим публичный адрес API, но не пароль базы и не ключ провайдера моделей. Изменение переменной уже запущенного nginx не переписывает собранный JavaScript: нужен новый build либо специально реализованная загрузка публичной конфигурации во время запуска.

Если API находится на другом домене, разрешите нужный origin в CORS на API. Не пытайтесь исправить серверные права доступа только настройкой фронтенда. Для своего домена используйте документацию приложений; полный стартовый проект доступен в static-react-vite.