import { execSync } from "child_process"; import { defineConfig, loadEnv } from "vite"; import react from "@vitejs/plugin-react"; import { VitePWA } from "vite-plugin-pwa"; import path from "path"; /** * Что именно сейчас открыто — видно на вкладке «Отладка». * * Без этого «правка не приехала» и «приехала, но кэш старый» выглядят * одинаково, а проверяются по-разному. Коммит берём из git; вне репозитория * (сборка из архива, CI без .git) — честный «unknown», а не падение сборки. */ function buildCommit(): string { try { return execSync("git rev-parse --short HEAD", { stdio: ["ignore", "pipe", "ignore"] }) .toString().trim() || "unknown"; } catch { return "unknown"; } } /** * Локальная разработка ходит в бэкенд ЧЕРЕЗ ПРОКСИ dev-сервера, а не напрямую. * * Почему не «разрешить localhost в CORS бэкенда»: через прокси запрос уходит с * того же origin, что и страница (http://localhost:5174/api/...), поэтому CORS * в разработке не участвует вообще — ни preflight, ни credentials. Боевой * список origin'ов на бэкенде остаётся закрытым, и CORS_ALLOW_LOCALHOST ради * этого фронта включать не нужно. * * Дефолтная цель прокси — ЛОКАЛЬНЫЙ бэкенд, а не crm.pptaxi.ru. Контур боевой: * «по умолчанию проксировать в прод» означало бы, что первый же тычок в * «Пополнить» на машине разработчика создаёт платёж на живом терминале и живой * чек 54-ФЗ. Другой адрес задаётся VITE_API_TARGET — тем же именем, что в CRM * (crm2/frontend/vite.config.ts), чтобы рецепт был один на оба фронта. */ export default defineConfig(({ command, mode }) => { // База для ky (src/api/client.ts): в dev — свой же origin, дальше прокси. // Ставим ТОЛЬКО если разработчик не задал базу сам (.env.local, .env, // VITE_API_BASE=... перед командой): loadEnv отдаёт и файлы, и process.env, // причём process.env приоритетнее файлов — без этой проверки собственная // настройка молча перебивалась бы нашим дефолтом. // В сборку (command === "build") не лезем никогда: там база остаётся боевой — // из .env, либо из дефолта в client.ts. if (command === "serve" && !loadEnv(mode, __dirname, "VITE_").VITE_API_BASE) { process.env.VITE_API_BASE = "/api"; } return { define: { __BUILD_COMMIT__: JSON.stringify(buildCommit()), __BUILD_TIME__: JSON.stringify(new Date().toISOString().slice(0, 16).replace("T", " ")), }, plugins: [ react(), // injectManifest, а не generateSW: воркер свой, потому что уведомления // показывает он (см. src/sw.ts), а сгенерированный умеет только кэш. VitePWA({ strategies: "injectManifest", srcDir: "src", filename: "sw.ts", registerType: "autoUpdate", manifest: false, includeAssets: ["icons/*.png"], injectManifest: { globPatterns: ["**/*.{js,css,html,png,svg,webmanifest}"] }, }), ], resolve: { alias: { "@": path.resolve(__dirname, "src") } }, server: { port: 5174, proxy: { "/api": { // secure: false нужен только для VITE_API_TARGET на https-цель с // самоподписанным сертификатом; на дефолтную http-цель не влияет. target: process.env.VITE_API_TARGET || "http://127.0.0.1:8000", changeOrigin: true, secure: false, }, }, }, }; });