记录--你还在傻傻的npm run serve吗?快来尝尝这个!
Posted 林恒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录--你还在傻傻的npm run serve吗?快来尝尝这个!相关的知识,希望对你有一定的参考价值。
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
背景
大家在日常开发中应该经常会有需要切换不同环境地址的情况。当一个项目代码切换环境地址时,vue-cli没有能够感知文件的变化,所以代理的还是旧的地址,所以通常我们需要执行npm run serve
进行项目重跑,而项目重跑往往意味着长时间的等待,非常痛苦!
方案调研
事实上,其实我们只是需要重启webpack为我们启动的proxy代理服务
,或许能够从webpack的代理服务插件中找到解决方法。
从webpack官网可以看到proxy服务其实是由 http-proxy-middleware提供的,或许我们能够从中找到解决方法。
初步方案
在http-proxy-middleware的配置选项中,除了我们常见的target,还有router。router返回一个字符串的服务地址,当两个选项都配置了的情况下,会优先使用router函数的返回值,只有当router的返回值不可用时,才会使用target的值。
我们可以利用这一点来重新配置我们的项目代码。参考文档在这里
// vue.config.js const defineConfig = require(\'@vue/cli-service\') const proxy = require(\'./environments/proxy.js\') module.exports = defineConfig( devServer: proxy , )
// proxy.js const fs = require(\'fs\') const path = require(\'path\') const encoding = \'utf-8\' const getContent = filename => const dir = path.resolve(process.cwd(), \'environments\') return fs.readFileSync(path.resolve(dir, filename), encoding ) const jsonParse = obj => return Function(\'"use strict";return (\' + obj + \')\')() const getConfig = () => try return jsonParse(getContent(\'proxy-config.json\')) catch (e) return module.exports = proxy: // 接口匹配规则自行修改 \'/api\': // 这里必须要有字符串来进行占位 // 如果报错Invaild Url,将target改成有效的url字符串即可,如http://localhost:9001 target: \'that must have a empty placeholder\', changeOrigin: true, router: () => (getConfig() || ).target || \'\'
// proxy-config.json "target": "http://localhost:9001"
自此,当我们需要修改环境地址时,只需要修改proxy-config.json
文件便能够实时生效,不再需要npm run serve
!
重点代码分析
实现代码中其实最主要的就是getContent
这个方法,我们项目在每次发起http请求时都会调用router中的函数
,而getContent则会通过node的fs服务,对我们的环境地址文件进行实时读取
,从而指向我们最新修改的环境地址。
方案总结
在按照参考文档配置了项目代码之后,我们发现确实能够及时指向新的环境地址,再也不需要重启代码,不需要长时间的等待了。但是,我们多了两个需要维护的文件,每次我们修改环境地址时,不仅需要修改config中的api,还需要修改proxy-config.json中的target!
有没有可能在只需要修改config文件的情况下,实现代理地址动态修改
呢?
方案优化
从上面的重点代码分析中,可以看到只要我们可以在router函数执行时,拿到正确的config文件中导出的api属性的值,也可以实现同样的效果!
这是不是意味着只要我们在函数中对config文件进行require请求,读取api的值,再return出去就能及时修改代理指向了呢?
没错,你会发现无论你怎么修改,函数内require取到的api永远是不变的,还是服务刚启动时的环境地址。
参考源码可以知道,这是因为我们在使用require请求文件信息时,node会解析出我们传入的字符串的文件路径的绝对路径,并且以绝对路径为键值,对该文件进行缓存
。
因此,如果我们在执行require函数时打断点进行观察的话,会发现require上面有一个cache缓存了已经加载过的文件。
这也恰恰说明了只要我们能够删除掉文件保存在require中的缓存,我们就能够拿到最新的文件内容,那么我们也可以据此得出我们的最终优化方案。
// vue.config.js const hotRequire = modulePath => // require.resolve可以通过相对路径获取绝对路径 // 以绝对路径为键值删除require中的对应文件的缓存 delete require.cache[require.resolve(modulePath)] // 重新获取文件内容 const target = require(modulePath) return target ... proxy: \'/api\': // 如果router有效优先取router返回的值 target: \'that must have a empty placeholder\', changeOrigin: true, // 每次发起http请求都会执行router函数 router: () => (hotRequire(\'./src/utils/config\') || ).api || \'\', ws: true, pathRewrite: \'^/api\': \'\'
自此,我们项目修改环境地址将不在需要重启项目,也不需要维护额外的文件夹,再也不需要痛苦等待了!
本文转载于:
https://juejin.cn/post/7198696282336313400
如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。
以上是关于记录--你还在傻傻的npm run serve吗?快来尝尝这个!的主要内容,如果未能解决你的问题,请参考以下文章
vue项目启动时,npm run serve 和 npm run dev 的区别