import { defineConfig, loadEnv } from 'vite' import vue from '@vitejs/plugin-vue' import { resolve } from 'path' import { fileURLToPath, URL } from 'node:url' import Icons from 'unplugin-icons/vite' import IconsResolver from 'unplugin-icons/resolver' import Components from 'unplugin-vue-components/vite' import path from 'node:path' import fs from 'node:fs' import { createRequire } from 'node:module' import { vitePluginPrerender } from './scripts/vite-plugin-prerender.js' // 统一处理后端 Set-Cookie,移除 Secure 标志,便于在 HTTP 开发环境保存 Cookie const cookieRewriteConfigure = (proxy: any) => { proxy.on('proxyRes', (proxyRes: any) => { const setCookieHeaders = proxyRes.headers['set-cookie'] if (setCookieHeaders) { proxyRes.headers['set-cookie'] = setCookieHeaders.map((cookie: string) => { return cookie .replace(/;\s*[Ss]ecure/gi, '') .replace(/,\s*[Ss]ecure/gi, '') }) } }) } // 读取 apps.txt 确定应用优先级(靠后优先) function loadAppsOrder(appsDir: string) { const appsTxt = path.join(appsDir, 'apps.txt') try { const content = fs.readFileSync(appsTxt, 'utf-8') return content .split(/\r?\n/) .map((s) => s.trim()) .filter(Boolean) } catch { return ['jingrow'] } } // 计算本工程中的 apps 目录(当前文件位于 apps/jingrow/frontend/vite.config.ts) const currentDir = fileURLToPath(new URL('.', import.meta.url)) const appsDir = path.resolve(currentDir, '..', '..') const APPS_ORDER = loadAppsOrder(appsDir) export default defineConfig(({ mode, command }) => { const env = loadEnv(mode, process.cwd(), '') const BACKEND_URL = env.VITE_BACKEND_SERVER_URL || 'http://localhost' const FRONTEND_HOST = env.VITE_FRONTEND_HOST || '0.0.0.0' const FRONTEND_PORT = Number(env.VITE_FRONTEND_PORT) || 3100 const ALLOWED_HOSTS = (env.VITE_ALLOWED_HOSTS || '').split(',').map((s) => s.trim()).filter(Boolean) // 开发环境:文件目录路径 const filesDir = command === 'serve' ? path.resolve(currentDir, '..', 'jingrow', 'public', 'files') : null return { plugins: [ vue(), Icons({ autoInstall: true, compiler: 'vue3' }), Components({ resolvers: [ IconsResolver({ prefix: 'i', enabledCollections: ['tabler'] }), ], }), // 开发环境:直接服务文件系统 command === 'serve' && filesDir && { name: 'serve-files', configureServer(server) { const require = createRequire(import.meta.url) const serve = require('serve-static')(filesDir, { index: false }) server.middlewares.use('/files', serve) } }, // 预渲染插件(仅在构建时启用) command === 'build' && vitePluginPrerender({ // 路由列表会自动从工具 store 生成 // 也可以手动指定:routes: ['/', '/tools', '/tools/remove-background'] rendererOptions: { maxConcurrentRoutes: 4, timeout: 30000, waitUntil: 'networkidle0' } }) ].filter(Boolean), resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), // 跨 app 访问源码(相对计算得到的 apps 目录) '@apps': appsDir } }, server: { host: FRONTEND_HOST, port: FRONTEND_PORT, strictPort: true, open: false, cors: true, // 允许通过指定域名访问开发服务器(可通过 VITE_ALLOWED_HOSTS 配置,逗号分隔) ...(ALLOWED_HOSTS.length ? { allowedHosts: ALLOWED_HOSTS } : {}), fs: { // 放行 monorepo apps 目录,便于 import.meta.glob 跨应用扫描 allow: [appsDir] }, proxy: { '/api/action': { target: BACKEND_URL, changeOrigin: true, secure: false, cookieDomainRewrite: { '*': '' }, cookiePathRewrite: { '*': '/' }, configure: cookieRewriteConfigure } } }, build: { outDir: 'dist', assetsDir: 'assets', sourcemap: false, chunkSizeWarningLimit: 2000 }, define: { // 确保环境变量在构建时可用 __APP_VERSION__: JSON.stringify(process.env.npm_package_version), // 注入 apps.txt 的应用顺序到前端 __APPS_ORDER__: JSON.stringify(APPS_ORDER) } } })