/// import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import { TanStackRouterVite } from '@tanstack/router-vite-plugin' import path from 'path' import { execSync } from 'node:child_process' import { readFileSync } from 'node:fs' // Build identity injected at compile time. Used by VersionBadge / UpdateBanner. // // Priority chain (most authoritative first): // 1. CI_COMMIT_TAG → set ONLY on tag pipelines (e.g. "v1.3.1"). Это source // of truth для release builds. Strip leading 'v' → "1.3.1". // 2. package.json.version → fallback floor для local dev и branch builds. // НЕ обновляется вручную — release flow добавит автоматический bump // позже (release script tag + npm version в одном commit'е). // // __APP_TAG__ — пустая строка если не tag build. VersionBadge решает что // показать (приоритет: serverTag → clientTag → v${clientVersion}). // // __APP_COMMIT__ — 8-char short SHA. CI передаёт через CI_COMMIT_SHORT_SHA // (GitLab default 8 chars), local через `git rev-parse --short=8`. const APP_VERSION: string = JSON.parse( readFileSync(path.resolve(__dirname, 'package.json'), 'utf-8'), ).version // 'none' — Dockerfile default ARG value (см. .gitlab-ci.yml passes // --build-arg GIT_TAG="${CI_COMMIT_TAG:-none}"). Filter → пустая строка. const RAW_TAG = process.env.CI_COMMIT_TAG ?? '' const APP_TAG: string = RAW_TAG === 'none' ? '' : RAW_TAG.replace(/^v/, '') // GitLab CI ставит CI=true. Используем для discriminate "CI branch build" // (нет tag'а, но есть pipeline) vs "local pnpm dev" (нет ни того ни другого). // VersionBadge показывает 'dev' для первого, 'local' для второго. const APP_CI: boolean = process.env.CI === 'true' const APP_COMMIT: string = process.env.CI_COMMIT_SHORT_SHA ?? (() => { try { return execSync('git rev-parse --short=8 HEAD', { stdio: ['ignore', 'pipe', 'ignore'] }) .toString() .trim() } catch { return 'unknown' } })() const APP_BUILT_AT: string = new Date().toISOString() export default defineConfig({ define: { __APP_VERSION__: JSON.stringify(APP_VERSION), __APP_TAG__: JSON.stringify(APP_TAG), __APP_CI__: JSON.stringify(APP_CI), __APP_COMMIT__: JSON.stringify(APP_COMMIT), __APP_BUILT_AT__: JSON.stringify(APP_BUILT_AT), }, test: { environment: 'jsdom', setupFiles: ['./src/test/setup.ts'], globals: true, css: false, }, plugins: [ TanStackRouterVite({ routesDirectory: 'src/routes', generatedRouteTree: 'src/routeTree.gen.ts' }), react(), tailwindcss(), ], resolve: { alias: { '@': path.resolve(__dirname, 'src'), }, }, server: { host: '0.0.0.0', port: 5173, proxy: { '/api': { target: process.env.VITE_API_PROXY ?? 'http://localhost:8080', changeOrigin: true, // secure: false нужен когда target — HTTPS endpoint с self-signed // сертификатом (port-forward с локальным CA или внутренний cluster // service). Для prod/staging Let's Encrypt cert validation не нужно // отключать но игнор не вредит для dev mode. secure: false, // ws: true — на будущее когда Server-Sent Events / WebSocket каналы // появятся (real-time notifications, audit stream). ws: true, }, }, }, build: { chunkSizeWarningLimit: 600, rollupOptions: { output: { // Группировка по принципу: что меняется редко → отдельный chunk → // браузер кэширует надолго. Что меняется часто (наш код) — в main. manualChunks: (id) => { if (!id.includes('node_modules')) return undefined // React core — стабильный, основа всего if (id.match(/node_modules\/(react|react-dom|scheduler)\//)) return 'vendor-react' // TanStack — Router + Query, крупные но стабильные if (id.includes('node_modules/@tanstack/')) return 'vendor-tanstack' // @nstart/ui — самый тяжёлый: brand stickers/animations + tons of UI // (проверяй динамически: lottie, echarts если есть, motion) if (id.includes('node_modules/@nstart/ui')) return 'vendor-nstart-ui' // Иконки — отдельно, ленивая загрузка эффективна if (id.includes('node_modules/@phosphor-icons/')) return 'vendor-icons' // Формы + JSON Schema валидация if (id.match(/node_modules\/(react-hook-form|@hookform|ajv|ajv-formats)\//)) { return 'vendor-forms' } // OIDC / auth if (id.match(/node_modules\/(oidc-client-ts|react-oidc-context)\//)) { return 'vendor-auth' } // i18next — отдельно if (id.match(/node_modules\/(i18next|react-i18next|i18next-browser-languagedetector)\//)) { return 'vendor-i18n' } // Axios + парсеры if (id.match(/node_modules\/(axios|jose|crypto-js)\//)) return 'vendor-net' // Остальное — в общий vendor (не должно быть много) return 'vendor-misc' }, }, }, }, })