import path from 'path'; import commonjs from 'vite-plugin-commonjs' import { defineConfig, loadEnv } from 'vite' import uni from '@dcloudio/vite-plugin-uni' import pkg from './package.json' // https://vitejs.dev/config/ // FRP 内网穿透绕过中间件 // FRP 默认拦截 URL 中包含 /node_modules/ 的请求返回 404 // 此中间件: // 1. 将响应内容中的 /node_modules/ 替换为 /__deps__/(浏览器请求时避开 FRP 拦截) // 2. 将传入请求中的 /__deps__/ 还原为 /node_modules/(Vite 才能正确处理) function frpBypassMiddleware() { return { name: 'frp-bypass', configureServer(server) { server.middlewares.use((req, res, next) => { // 重写传入请求:/__deps__/ → /node_modules/ if (req.url && req.url.includes('/__deps__/')) { req.url = req.url.replace(/\/__deps__\//g, '/node_modules/') } // 拦截传出响应,将 /node_modules/ 替换为 /__deps__/ const origEnd = res.end const chunks = [] res.write = function (chunk, ...args) { if (chunk != null) { chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk) } return true } res.end = function (chunk, ...args) { if (chunk != null) { chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk) } if (chunks.length === 0) { return origEnd.apply(res, arguments) } const fullBody = Buffer.concat(chunks) const ct = String(res.getHeader('content-type') || '') // 仅对文本类型响应进行替换 if (/text|javascript|json|xml|css/.test(ct)) { const bodyStr = fullBody.toString('utf-8') if (bodyStr.includes('/node_modules/')) { const replaced = bodyStr.replace(/\/node_modules\//g, '/__deps__/') res.setHeader('content-length', String(Buffer.byteLength(replaced, 'utf-8'))) return origEnd.call(res, replaced, ...args) } return origEnd.call(res, bodyStr, ...args) } // 非文本类型直接透传 return origEnd.call(res, fullBody, ...args) } next() }) }, } } export default defineConfig(({ mode }) => { // 根据当前 mode 加载对应 .env 文件中的环境变量 const env = loadEnv(mode, process.cwd(), 'VITE_') const apiTarget = env.VITE_APP_HOST || '' // 自定义 mode 列表,构建时追加到 outDir 末尾 const customModes = ['', 'csxg', 'xnet', 'qyyst', 'qycrg'] if (customModes.includes(mode)) { // 必须在 uni() 插件之前设置,这样 static/uni_modules 复制才会进子目录 process.env.UNI_OUTPUT_DIR = `dist/build/h5/${mode}/ABC_${mode}_patientapp_${pkg.version}` } else { process.env.UNI_OUTPUT_DIR = `dist/build/h5/ABC_patientapp_${pkg.version}` } // 从环境变量获取输出目录(uni-app CLI 已经设置好) const outDir = process.env.UNI_OUTPUT_DIR return { build: { outDir, }, plugins: [ uni(), commonjs(), // frpBypassMiddleware(), // FRP内网穿透绕过,非FRP环境可注释 // 强制覆盖 uni-app 设置的 build.outDir,确保 assets/index.html 也进 patientapp { name: 'force-outdir', enforce: 'post', config(config) { config.build = config.build || {}; config.build.outDir = outDir; } }, ], css: { preprocessorOptions: { scss: { api: 'modern-compiler' // 使用新的现代编译器API,避免旧版JS API弃用警告 } } }, resolve: { alias: { '@vue/shared': '@vue/shared/dist/shared.esm-bundler.js', '@': 'src', 'jweixin-module': path.resolve(__dirname, 'src/js_sdk/jweixin-module/index.js') } }, server: { host: '0.0.0.0', allowedHosts: [ 'frp.12123wzcx.com', // 允许所有 frp.12123wzcx.com 的子域名 ], proxy: { '/wechatbdhealth': { target: apiTarget, changeOrigin: true, rewrite: (path) => path.replace('/wechatbdhealth', '/wechatbdhealth') }, '/patientapp/images': { target: apiTarget, changeOrigin: true, rewrite: (path) => path.replace('/patientapp/images', '/images') }, '/uploadFile': { target: apiTarget, changeOrigin: true, rewrite: (path) => path.replace('/uploadFile', '/uploadFile') }, '/images': { target: apiTarget, changeOrigin: true, rewrite: (path) => path.replace('/images', '/images') }, // '/MP_verify_mRdA5h8p5Phywrus.txt': { // target: 'http://localhost:81', // changeOrigin: true, // rewrite: (path) => path.replace('/MP_verify_mRdA5h8p5Phywrus.txt', '/MP_verify_mRdA5h8p5Phywrus.txt') // }, '/ws/': { target: 'https://apis.map.qq.com', changeOrigin: true, rewrite: (path) => path.replace('/ws/', '/ws/') }, '/fileUp/': { target: 'https://np.h03.p0551.com', changeOrigin: true, rewrite: (path) => path.replace('/fileUp/', '') }, '/pingd': { target: 'https://pingtas.qq.com', changeOrigin: true, }, } }, } })