You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.2 KiB

5 months ago
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
5 months ago
import dns from 'node:dns'
// 解决 Node.js 17+ 默认使用 IPv6 导致无法连接 localhost 的问题
try {
dns.setDefaultResultOrder('ipv4first')
} catch (e) {
console.warn('Failed to set DNS result order to ipv4first', e)
}
5 months ago
export default defineConfig(({ mode }) => {
// 加载环境变量
const env = loadEnv(mode, process.cwd(), '')
5 months ago
5 months ago
// 开发环境必须配置代理目标
if (mode === 'development') {
if (!env.VITE_API_PROXY_TARGET) {
throw new Error(
'❌ 错误: 开发环境必须配置 VITE_API_PROXY_TARGET 环境变量\n' +
'请在 .env.development 文件中添加:\n' +
'VITE_API_PROXY_TARGET=http://czemc.localhost\n' +
'\n' +
'示例:\n' +
'VITE_API_PROXY_TARGET=http://czemc.localhost\n' +
'或\n' +
'VITE_API_PROXY_TARGET=http://localhost:8000'
)
}
5 months ago
// 打印代理配置信息
console.log('🔧 Vite 代理配置:', {
target: env.VITE_API_PROXY_TARGET,
mode: mode
})
5 months ago
}
5 months ago
5 months ago
return {
5 months ago
// 配置基础路径,使用相对路径以支持子路径部署
// 如果部署在根路径,可以设置为 '/'
// 如果部署在子路径(如 /budget/),使用相对路径 './' 更灵活
base: env.VITE_BASE_PATH || './',
5 months ago
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
port: 3000,
5 months ago
open: true,
proxy: mode === 'development' ? {
// 代理所有 /api 请求到后端服务器
'/api': {
target: env.VITE_API_PROXY_TARGET,
changeOrigin: true,
secure: false,
5 months ago
ws: true,
// 添加 X-Forwarded-* 头
xfwd: true,
// 不重写路径
rewrite: (path) => path,
// 添加代理日志和错误处理
configure: (proxy, options) => {
// 如果配置了 VITE_API_PROXY_HOST_HEADER则强制设置 Host 头
// 这对于后端配置了虚拟主机Virtual Host的情况非常有用
if (env.VITE_API_PROXY_HOST_HEADER) {
proxy.on('proxyReq', (proxyReq) => {
proxyReq.setHeader('Host', env.VITE_API_PROXY_HOST_HEADER)
})
}
console.log('✅ 代理中间件已配置:', {
target: options.target,
path: '/api'
})
proxy.on('proxyReq', (proxyReq, req, res) => {
const targetUrl = `${options.target}${req.url}`
console.log(`➡️ [代理转发] ${req.method} ${req.url}`)
console.log(` → 目标地址: ${targetUrl}`)
console.log(` → Host 头: ${proxyReq.getHeader('host')}`)
console.log(` → 请求头:`, JSON.stringify(proxyReq.getHeaders(), null, 2))
})
proxy.on('proxyRes', (proxyRes, req, res) => {
console.log(`⬅️ [代理响应] ${req.url} -> ${proxyRes.statusCode}`)
console.log(` → 响应头:`, JSON.stringify(proxyRes.headers, null, 2))
})
proxy.on('error', (err, req, res) => {
console.error(`❌ [代理错误] ${req.url}:`, err.message)
console.error(` 错误代码: ${err.code}`)
console.error(` 错误详情:`, {
code: err.code,
errno: err.errno,
syscall: err.syscall,
address: err.address,
port: err.port,
stack: err.stack
})
// 尝试发送错误响应
if (res && !res.headersSent) {
try {
res.writeHead(500, {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
})
res.end(JSON.stringify({
code: 500,
msg: '代理服务器错误',
error: err.message,
errorCode: err.code
}))
} catch (e) {
console.error('无法发送错误响应:', e)
}
}
})
},
// 保持请求路径不变,直接转发到目标服务器
// 例如: /api/budget/xxx -> http://czemc.localhost/api/budget/xxx
5 months ago
}
} : undefined
5 months ago
},
// 定义全局常量替换
define: {
// 确保环境变量在构建时被正确替换
__APP_ENV__: JSON.stringify(env.VITE_APP_ENV || mode)
},
// 构建配置
build: {
5 months ago
// 从环境变量读取构建输出目录,如果没有则使用默认值
outDir: env.VITE_BUILD_OUT_DIR || 'dist',
5 months ago
sourcemap: mode === 'development',
// 根据环境输出不同的构建产物名称
rollupOptions: {
output: {
// 可以根据环境自定义输出文件名
entryFileNames: `assets/[name].${mode}.js`,
chunkFileNames: `assets/[name].${mode}.js`,
assetFileNames: `assets/[name].${mode}.[ext]`
}
}
}
}
})