Vue2+不重啟/發(fā)版,客戶端刷新即可切換接口地址的一種實(shí)施方案
開發(fā)背景:
日常經(jīng)常需要切換到不同伙伴開發(fā)的接口上,例如還未提交/不能提交的接口,或是協(xié)助斷點(diǎn)調(diào)試等等,戳中打1。
線上服務(wù)器撞山垮塌崩,沒有HS需要改接口地址,重新pack發(fā)版都嫌慢的,戳中打2。
本方案目前只在Vue的2和3兩個(gè)上使用過(guò),其他需要打包的框架應(yīng)該也能類比吧,沒一一測(cè)試,無(wú)框大佬鄙人幫不上的就只能謝謝點(diǎn)贊了。
知識(shí)點(diǎn):
原生XMLHttpRequest,localStorage,async/await或Promise
方案思路:
打包的項(xiàng)目由于配置是一起被固化到了代碼內(nèi),所以想要變更這些固定配置,但不重新打包,需要將這些寫好的配置改為通過(guò)其他途徑去獲取,那么數(shù)一下前端能夠自力更生的方案里,new一個(gè)XMLHttpRequest去拉配置是最簡(jiǎn)單的。
配置的獲取方式確定了,就需要再確定一個(gè)獲取的時(shí)點(diǎn),想想Vue在每個(gè)訪問(wèn)連接打開發(fā)生時(shí)候都干了啥(不是指tcp握手之類的ho~),訪問(wèn)到index,new一個(gè)vue實(shí)例,那么跑去main看看,好,里面還是有可以創(chuàng)作的空間的,那么我們就可以在Main腳本里執(zhí)行我們拉配置的方法。
現(xiàn)在剩下的問(wèn)題就是怎么把dev環(huán)境的proxy以及prod下的接口地址改成動(dòng)態(tài)的,還是回到項(xiàng)目代碼里,找到相關(guān)的兩處來(lái)分析,首先解決dev的,以vite為例子,vite配置里的{ server?}節(jié)點(diǎn)的proxy,即是配置接口目標(biāo)代理的位置,通常就是寫一個(gè)target/rewrite即可,如果是多個(gè)目標(biāo)地址,建議采用一個(gè)單獨(dú)的腳本去生成,稍后下文會(huì)上具體代碼。其次prod的,由于生產(chǎn)環(huán)境下一般不走proxy(KOA服務(wù)進(jìn)行代理的不算),所以只需要關(guān)注如何改變BaseURL即可(我默認(rèn)是用Axios哈,其他的請(qǐng)求庫(kù)或者手寫的請(qǐng)求器也類似,關(guān)注如何改變接口地址域名),同樣稍后會(huì)有具體代碼伺候。整個(gè)方案其實(shí)都很Easy來(lái)的,都是一些基礎(chǔ)內(nèi)容。
Coding過(guò)程:
下面都是Vue3的例子,Vue2也能用,但是文件位置等可能會(huì)有變化,我這里沒用TS(別問(wèn)為什么不TS,問(wèn)就是不會(huì)),而且項(xiàng)目結(jié)構(gòu)是按照個(gè)人習(xí)慣來(lái)的,不建議照搬,搞代碼一定要魂,要有自己的風(fēng)格。
涉及到改動(dòng)的兩個(gè)固定文件:vite.config.js,main.js;
需要增加的代碼塊:負(fù)責(zé)生成dev環(huán)境下的proxy清單的方法,負(fù)責(zé)獲取配置的方法;
額外增加的配置文件兩個(gè),分別對(duì)應(yīng)development和production兩個(gè)環(huán)境。
分別按照步驟一一說(shuō)明:
首先創(chuàng)建一個(gè)負(fù)責(zé)生成dev環(huán)境下的proxy清單的方法的模塊

這段代碼的作用就是給vite.config.js獲取代理配置所用,targets為需要對(duì)接的所有服務(wù)器地址,也可以用好辨識(shí)的名字,比如我實(shí)際上用的就是其他伙伴姓名的拼音縮寫;generateProxySetting是根據(jù)targets的內(nèi)容遍歷key,并根據(jù)key的名稱生成proxy數(shù)據(jù)組,proxies為存放生成的proxy數(shù)據(jù)的空對(duì)象,也可以預(yù)設(shè)需要的數(shù)據(jù),比如我在這里放的就是mock接口數(shù)據(jù);useProxyTable則是最終將targets給處理成可用的proxy數(shù)據(jù)的方法,把上述內(nèi)容組織起來(lái),并導(dǎo)出useProxyTable方法備用。
接下來(lái)是vite.config.js的改動(dòng)


然后需要?jiǎng)?chuàng)建配置的JSON文件
配置文件需要?jiǎng)?chuàng)建到項(xiàng)目的public下,以便項(xiàng)目能夠在打包后可以正常加載到(public作為vue項(xiàng)目的靜態(tài)資源應(yīng)該都知道吧),比如我是使用的public/config路徑(config自己創(chuàng)建)

這里配置文件的命名建議里面包含環(huán)境的標(biāo)識(shí)符,譬如development/production這種(稍后你就知道為啥了,問(wèn)就是就是懶)。

再就是獲取配置文件的方法

圖思:根據(jù)當(dāng)前打包環(huán)境匹配到需要使用的json文件名,然后通過(guò)ajax獲取到配置,再存到緩存里,整體需要考慮到一個(gè)異步順序問(wèn)題;我數(shù)據(jù)暫存用的pinia,類似vuex的功能,如果項(xiàng)目里面沒有用到store概念的,可以直接存localStorage/sessionStorage,只要能讓后續(xù)調(diào)用出來(lái)就成。
還是一個(gè)個(gè)的來(lái)講:envString為當(dāng)前的環(huán)境標(biāo)識(shí)(vite的寫法),webpack獲取途徑可能會(huì)不一樣;bootFileUrl為配置文件的存放位置,供ajax使用;getConfig為獲取配置文件的方法,原始的ajax寫法,然后輸出一個(gè)返回對(duì)象,我這里是為了和后臺(tái)接口格式統(tǒng)一所以附加了幾個(gè)字段;boot為輸出供Main.js調(diào)用的方法,負(fù)責(zé)調(diào)用getConfig獲取配置并存到緩存,這里為了確保異步順序,使用async/await來(lái)控制并確保各個(gè)步驟完成。
boot方法是整個(gè)的核心,這里主要是將你的JSON內(nèi)容轉(zhuǎn)換成對(duì)象,并儲(chǔ)存在對(duì)應(yīng)的緩存區(qū)內(nèi),如果你用了狀態(tài)管理,在后續(xù)就直接使用狀態(tài)管理提供的值就好;如果使用的是Storage類的,則切記獲取時(shí)候JSON.parse一下ho~
Main.js的改動(dòng)
快完了快完了…Main.js的作用不贅述了,很適合搞一些創(chuàng)作在里面的,這里需要改動(dòng)的就是加入獲取配置方法的調(diào)用,還是直接上圖

我這里是在createApp后調(diào)用的boot,因?yàn)槲倚枰A(yù)先初始化store里面的內(nèi)容,故app要先行創(chuàng)建(pinia的狀態(tài)管理模塊需要這樣,具體可以參考下pinia的文檔,此處說(shuō)個(gè)題外話,pinia雖然新但是API類似vuex,精簡(jiǎn)掉了mutation,與vue3的組合式API配合良好)。
注意:await boot()這里,如果編譯不過(guò)去,請(qǐng)參考top-level-await這個(gè)關(guān)鍵詞的相關(guān)搜索,可能需要安裝一個(gè)模塊。
請(qǐng)求封裝文件的改動(dòng)
好累,最后一步了,我就直接放出我的代碼吧,其他的封裝方式大同小異,都是集中在獲取緩存,然后組裝實(shí)際訪問(wèn)地址

打完收工,我們看看實(shí)際訪問(wèn)時(shí)候的效果
DEV環(huán)境下





這里利用了devServer的proxy特性,然后設(shè)置proxies里面對(duì)應(yīng)的key就能轉(zhuǎn)換出相應(yīng)的主機(jī)地址。
PROD環(huán)境下


這里緩存的就是直接的地址了,由于生產(chǎn)環(huán)境沒有使用proxy,所以請(qǐng)求封裝那里就會(huì)直接使用這個(gè)配置里的信息,后面的圖就不上了。
以上,歡迎提問(wèn)和反駁,互通有無(wú)。