vite前端项目运行时切换代理

📅 发布时间:2026/7/4 7:41:59 👁️ 浏览次数:
vite前端项目运行时切换代理
vite前端项目运行时切换代理背景vite前端项目开发时经常需要切换后端服务环境进行接口联调频繁修改 vite 配置并且在多人协作前端项目中经常会把 vite 配置改动提交的代码仓库导致代码冲突的问题频频发生。痛点频繁修改配置文件多人协作导致代码冲突。需求不需要修改配置文件的情况也能进行后端服务环境的切换提高开发效率。解决方案vite 自定义插件 切换后端服务环境的界面实现思路写一个 vite 自定义插件在 configureServer 钩子中自定义 middleware 中去拦截切换代理的 post 请求 /switch_env在界面上切换后端服务环境的时候发送 /switch_env 请求在运行时修改 vite 实例配置。也就是 vite.config.js 中的 proxy.target 修改为指定后端服务地址。修改完 vite 配置后自动 reload page。即完成后端服务的切换动作不需要每次都去修改 vite 配置。第一版具体实现实现 vite 插件 proxy-switch-vite-plugin.js引入到 vite.config.js实现 ui 组件 switch-env.vue引入到 App.vue。vite插件核心实现// proxy-switch-vite-plugin.jsimporttype{Plugin}fromviteconstENV_MAP{server1:http://localhost:3001,server2:http://localhost:3002}exportfunctionproxySwitchPlugin():Plugin{letserver:anyreturn{name:vite-plugin-proxy-switch,apply:serve,configureServer(viteServer){serverviteServer// 处理环境切换请求server.middlewares.use(/__switch_env,(req:any,res:any){if(req.method!POST)returnletbodyreq.on(data,(chunk:any){bodychunk.toString()})req.on(end,(){const{env,customUrl}JSON.parse(body)consttargetenvcustom?customUrl:ENV_MAP[env]// 动态更新代理目标applyTarget(server,target)res.writeHead(200,{Content-Type:application/json})res.end(JSON.stringify({ok:true,env,target}))})})}}}// 动态更新代理配置的核心函数functionapplyTarget(server:any,target:string){if(!server.config.server?.proxy)returnconstproxyserver.config.server.proxyasRecordstring,anyObject.keys(proxy).forEach(key{if(proxy[key]){proxy[key].targettarget console.log(Updated proxy for${key}to target:${target})}})}UI组件实现!-- switch-env.vue -- template div classenv-switcher div classenv-container span当前环境: {{ currentEnv }}/span el-select v-modelselectedEnv changehandleEnvChange el-option labelServer 1 valueserver1 / el-option labelServer 2 valueserver2 / /el-select /div /div /template script setup import { ref } from vue const currentEnv ref(server1) const selectedEnv ref(server1) const handleEnvChange async () { try { const response await fetch(/__switch_env, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ env: selectedEnv.value }) }) if (response.ok) { const result await response.json() currentEnv.value result.env localStorage.setItem(proxy-env, JSON.stringify(result)) setTimeout(() window.location.reload(), 500) } } catch (error) { console.error(切换环境出错:, error) } } /script style scoped ... /style在App.vue中引入!-- App.vue -- template div classapp EnvSwitch / RouterView / /div /template script setup import EnvSwitch from ./components/switch-env.vue /script缺点第一版解决问题满足需求但是 ui 组件入侵业务代码这点不是很好。第二版vue 组件运行时注入改进ui 组件在运行时注入到 App.vue 中,在自定义 vite 插件的 transform 中注入 vue 组件。虚拟模块实现// vite-plugin-proxy-switch.tsconstVIRTUAL_IDvirtual:env-switch.vueconstRESOLVED_ID/virtual/env-switch.vuefunctiongetEnvSwitchSFC():string{returntemplate div classenv-switcher el-select v-modelselectedEnv changehandleEnvChange el-option labelServer 1 valueserver1 / el-option labelServer 2 valueserver2 / el-option label自定义 valuecustom / /el-select /div /template script setup import { ref } from vue const selectedEnv ref(server1) const handleEnvChange async () { // 切换逻辑... } /script style scoped .env-switcher { position: fixed; top: 0; left: 0; right: 0; background: #409eff; padding: 10px; } /style}exportfunctionproxySwitchPlugin():Plugin{return{name:vite-plugin-proxy-switch,apply:serve,resolveId(id){if(idVIRTUAL_ID)returnRESOLVED_ID},load(id){if(idRESOLVED_ID)returngetEnvSwitchSFC()},transform(code,id){// 过滤掉子块请求和非 App.vue 文件if(!id.includes(App.vue)||id.includes(?))returnletmodifiedcode// 动态导入虚拟模块if(!code.includes(VIRTUAL_ID)){modifiedmodified.replace(import { RouterView } from vue-router,import EnvSwitch from ${VIRTUAL_ID}\nimport { RouterView } from vue-router)}// 动态添加组件到模板if(!code.includes(EnvSwitch)){modifiedmodified.replace(div classapp-container,div classapp-container\n EnvSwitch /)}if(modified!code)return{code:modified}}}}缺点每次启动开发环境都会启动该插件并不是每种情况都需要去启动该功能。第三版提高可控性改进在 npm scripts 中加一条 script启动开发环境的同时启动该功能通过 vite 变量来做启动/关闭该功能的控制 VITE_ENABLE_PROXY_SWITCH。环境变量控制插件加载// vite.config.tsimport{defineConfig,loadEnv}fromviteimportvuefromvitejs/plugin-vueimport{proxySwitchPlugin}from./vite-plugin-proxy-switchexportdefaultdefineConfig(({mode}){// 加载环境变量constenvloadEnv(mode,process.cwd(),)// 根据环境变量决定是否启用代理切换插件constplugins[vue(),]// 只有当 VITE_ENABLE_PROXY_SWITCH 为 true 时才加载代理切换插件if(env.VITE_ENABLE_PROXY_SWITCHtrue){plugins.unshift(proxySwitchPlugin())}return{plugins,server:{proxy:{/api:{target:http://localhost:3001,// 默认使用server1changeOrigin:true}}}}})npm脚本配置{scripts:{dev:vite,// 普通开发模式dev:proxy:VITE_ENABLE_PROXY_SWITCHtrue vite,// 启用代理切换start:server1:cd server1 npm start,start:server2:cd server2 npm start,dev:full:concurrently \npm run start:server1\ \npm run start:server2\ \npm run dev:proxy\}}插件中添加环境变量检查// vite-plugin-proxy-switch.tsexportfunctionproxySwitchPlugin():Plugin{letserver:any// 检查是否启用代理切换constenableProxySwitchprocess.env.VITE_ENABLE_PROXY_SWITCHtruereturn{name:vite-plugin-proxy-switch,apply:serve,resolveId(id){if(idVIRTUAL_IDenableProxySwitch)returnRESOLVED_ID},load(id){if(idRESOLVED_IDenableProxySwitch)returngetEnvSwitchSFC()},transform(code,id){// 如果未启用代理切换则不进行任何转换if(!enableProxySwitch)return// transform逻辑...},configureServer(viteServer){serverviteServer// 如果未启用代理切换则不配置中间件if(!enableProxySwitch)return// 中间件配置...}}}完整示例Demo仓库地址: https://github.com/chenjz08/demo/tree/main/02-proxy-switch-demo本仓库包含了proxy switch vite插件的完整实现包括前端Vue项目、后端Express服务器和完整的配置示例可直接克隆运行包含完整的使用说明和测试接口