import { defineConfig, loadEnv } from 'vite' import react from '@vitejs/plugin-react' // 单一配置文件 + 多环境 .env: // - .env.development / .env.production / .env.staging 中配置变量 // - 通过 loadEnv 读取并应用到开发服务器与代理 export default defineConfig(({ mode }) => { const env = loadEnv(mode, '.', '') const port = Number(env.VITE_PORT || 5173) const open = String(env.VITE_OPEN ?? 'true').toLowerCase() === 'true' || env.VITE_OPEN === '1' const proxyTarget = env.VITE_ADMIN_PROXY_PATH || 'http://127.0.0.1:9898' return { plugins: [ react({ babel: { plugins: [ ['@babel/plugin-proposal-decorators', { legacy: true }], ['babel-plugin-transform-typescript-metadata'], ['@babel/plugin-proposal-class-properties', { loose: true }], ['@babel/plugin-proposal-private-methods', { loose: true }], ['@babel/plugin-proposal-private-property-in-object', { loose: true }] ] } }) ], server: { port, open, proxy: { '/api': { target: proxyTarget, changeOrigin: true, ws: true, // 为 SSE 透传加固:禁用超时并保持连接 proxyTimeout: 0, timeout: 0, headers: { 'Connection': 'keep-alive' }, // 关键:在 dev 代理层面禁止缓冲/缓存,强制以 chunk 方式向浏览器侧回传,避免一次性聚合 configure: (proxy: any) => { // 移除 Accept-Encoding,避免后端压缩导致中间件缓冲 proxy.on('proxyReq', (proxyReq: any, req: any) => { const url: string = req?.url || '' if (url.includes('/run/stream')) { try { if (typeof proxyReq.removeHeader === 'function') proxyReq.removeHeader('accept-encoding') proxyReq.setHeader('accept', 'text/event-stream') proxyReq.setHeader('connection', 'keep-alive') } catch {} } }) proxy.on('proxyRes', (proxyRes: any, req: any, res: any) => { const url: string = req?.url || '' const ct: string = String(proxyRes.headers?.['content-type'] || '') const isSse = url.includes('/run/stream') || ct.includes('text/event-stream') if (!isSse) return try { // 直接改写后端返回头,确保为 SSE 且无长度/压缩 proxyRes.headers['content-type'] = 'text/event-stream; charset=utf-8' proxyRes.headers['cache-control'] = 'no-cache' proxyRes.headers['pragma'] = 'no-cache' proxyRes.headers['x-accel-buffering'] = 'no' delete proxyRes.headers['content-length'] delete proxyRes.headers['content-encoding'] // 同步确保 devServer 给浏览器的头一致,并尽早发送 res.setHeader('Content-Type', 'text/event-stream; charset=utf-8') res.setHeader('Cache-Control', 'no-cache') res.setHeader('Pragma', 'no-cache') res.setHeader('X-Accel-Buffering', 'no') if (typeof res.removeHeader === 'function') res.removeHeader('Content-Length') if (typeof res.removeHeader === 'function') res.removeHeader('Content-Encoding') if (typeof res.flushHeaders === 'function') res.flushHeaders() } catch {} }) } } } } } })