Files
mdm-ordinis/ordinis-admin-ui/vite.config.ts
T
2026-05-12 11:41:12 +00:00

160 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// <reference types="vitest" />
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/, '')
// Distinguish "CI branch build" (badge → 'dev') vs "local pnpm dev" (→ 'local').
// Canonical CI signal — наличие CI_COMMIT_SHORT_SHA (GitLab CI always sets).
// process.env.CI тоже check'аем но он НЕ пробрасывается через Docker ARG'и
// (см. ordinis-admin-ui/Dockerfile), поэтому SHORT_SHA — primary detect.
const APP_CI: boolean =
Boolean(process.env.CI_COMMIT_SHORT_SHA) || 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'
// Monaco editor — ~1.2MB gzip. Lazy через React.lazy в JsonEditor.tsx;
// separate chunk даёт on-demand загрузку только когда CreateModal
// открыт. Без isolated chunk Monaco попадал бы в vendor-misc
// (главная страница). Аналог graph3d HOTFIX'а ниже — НО Monaco
// не зависит от d3 utils, поэтому circular chunk риска нет.
if (id.match(/node_modules\/(@monaco-editor|monaco-editor)\//)) {
return 'vendor-monaco'
}
// HOTFIX: graph3d isolated chunk был причиной runtime "Super
// expression must either be null or a function" (cyclic chunk
// dependency vendor-misc ↔ vendor-graph3d ломает порядок
// initialization three.js class inheritance). Откатываем
// isolation — three.js + d3-shared идут в общий vendor-misc.
//
// Trade-off: vendor-misc вырастет до ~700kb gz (с three.js),
// default page load грузит three.js eager. Lazy advantage 3D
// mode потерян. Это acceptable hotfix чтобы вернуть сайт; clean
// chunk split с separate worker bundle / preload strategy —
// separate follow-up. См. также: React.lazy на DictionaryGraph3D
// остаётся валидным (component split), просто его vendor deps
// теперь в общем chunk.
return 'vendor-misc'
},
},
},
},
})