SFT/fryl_h5/vite.config.js

102 lines
4.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { fileURLToPath, URL } from 'node:url'
import { defineConfig, loadEnv } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
// 临时CORS规避方案(仅用于本地 npm run dev 调试真实后端,不用于生产构建),与根目录管理后台
// vite.config.js 的方案完全一致:在 .env.development.local(已被 .gitignore 的 *.local 规则
// 忽略,不会提交)中配置 DEV_API_PROXY_TARGET=真实后端地址,dev server 会把浏览器发往同源
// /api 的请求在 Node 端转发给真实后端;浏览器全程只与同源的 localhost:5174 通信,天然不触发
// 浏览器 CORS 检查。同时需要把该 .env.development.local 中的 VITE_API_BASE_URL 设为空字符串,
// 让 axios 走相对路径(同源),否则请求不会经过下面的代理规则。未配置 DEV_API_PROXY_TARGET 时
// proxy 为 undefined,行为与之前完全一致(直接请求 VITE_API_BASE_URL 指向的地址,默认走本地
// mock server)。
const proxy = env.DEV_API_PROXY_TARGET
? {
'/api': {
target: env.DEV_API_PROXY_TARGET,
changeOrigin: true,
cookieDomainRewrite: 'localhost',
configure: (proxyServer, options) => {
let seq = 0
const startTimeMap = new Map()
const LOG_MAX_LEN = 2000
// 内容过长(如人脸识别的base64图片)时截断,避免刷屏终端
const truncate = (str) => {
if (str.length <= LOG_MAX_LEN) return str
return `${str.slice(0, LOG_MAX_LEN)}...(已截断,原文共${str.length}字符)`
}
// 请求/响应体优先按JSON美化打印,非JSON内容按原文打印
const formatBody = (buf) => {
const text = buf.toString('utf-8')
if (!text) return ''
try {
return truncate(JSON.stringify(JSON.parse(text)))
} catch {
return truncate(text)
}
}
proxyServer.on('proxyReq', (proxyReq, req) => {
const id = ++seq
startTimeMap.set(req, { id, startAt: Date.now() })
// 强制真实后端返回未压缩内容,否则响应体是gzip二进制,日志打印会是乱码
proxyReq.setHeader('Accept-Encoding', 'identity')
const targetUrl = new URL(options.target)
const fullUrl = `${targetUrl.protocol}//${targetUrl.host}${proxyReq.path}`
// 在 http-proxy 内部把 req 自动 pipe 到 proxyReq 之前先挂上监听,
// 这样既能拿到完整请求体,又不影响正常转发流程
const chunks = []
req.on('data', (chunk) => chunks.push(chunk))
req.on('end', () => {
const body = formatBody(Buffer.concat(chunks))
console.log(`\n[REAL-API #${id}] → ${req.method} ${fullUrl}`)
if (body) console.log(` 请求体: ${body}`)
})
})
proxyServer.on('proxyRes', (proxyRes, req) => {
const meta = startTimeMap.get(req) || {}
const chunks = []
proxyRes.on('data', (chunk) => chunks.push(chunk))
proxyRes.on('end', () => {
const body = formatBody(Buffer.concat(chunks))
const cost = meta.startAt ? `${Date.now() - meta.startAt}ms` : ''
console.log(`[REAL-API #${meta.id ?? '?'}] ← ${proxyRes.statusCode} (${cost})`)
if (body) console.log(` 响应体: ${body}`)
startTimeMap.delete(req)
})
})
proxyServer.on('error', (err, req) => {
const meta = startTimeMap.get(req) || {}
console.log(`[REAL-API #${meta.id ?? '?'}] × 转发异常 ${req?.method} ${req?.url}: ${err.message}`)
startTimeMap.delete(req)
})
}
}
}
: undefined
return {
plugins: [vue()],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
// 与主项目管理后台(端口 5173)区分,避免本机同时开发两个工程时端口冲突
port: 5174,
proxy
}
}
})