緣起
在Electron的渲染程式中(也就是頁面程式碼中),
我們常常使用process.env來攜帶一些環境變數,
比如HTTP服務地址的基質,本地靜態資源的路徑等
這樣做主要有兩個目的
一個是方便開發者寫多個配置環境變數的檔案,區分生產環境、測試環境和開發環境
另一個是主程式和渲染程式共享一套環境變數,全域性任何一個地方都隨取隨用,非常方便
正因為如此,一般的編譯工具都不會動使用者的process物件
但Vite不一樣,Vite的作者認為Vite只是給Web(執行在瀏覽器中的)產品提供服務的,
所以編譯時把使用者的process物件吃掉沒關係,甚至可以拉一個完全不一樣的東西給開發者都沒影響
因為Web前端開發者用不到這個物件
哎,尤雨溪完全忽略了Electron開發者的感受
現象
用Vite建立一個Vue3專案,在入口檔案中輸出這兩個物件
console.log(process)
console.log(process.env)
然後用Vite編譯,Electron打包編譯的檔案,安裝並啟動Electron,開啟偵錯程式,
process物件的輸出如下(注意process下env屬性是正常的):
process.env物件的輸出如下:
為什麼會出現這種現象呢?我們開啟Vite編譯後的檔案,找到目標位置,發現程式碼被轉化成了這個樣子:
console.log(process);
console.log({NODE_ENV: "production"});
process還是老樣子,但process.env被直接轉成了一個物件字面量
原理
想來Vite這麼做可能的原因是:
在process.env下加屬性是Node.js開發者最常用的區分生產環境和開發環境的方案了
但瀏覽器環境下根本就沒有process物件,那怎麼辦呢?
就直接粗暴的改寫了開發者的程式碼吧
把process.env轉碼成了{NODE_ENV: "production"}
於是,就是現在我們看到的結果
翻翻Vite的程式碼,確實找到了如下邏輯(這是最新的程式碼,以前我看到的跟這還不一樣):
createReplacePlugin( (id) => !/\?vue&type=template/.test(id) && // also exclude css and static assets for performance !isCSSRequest(id) && !resolver.isAssetRequest(id), { ...defaultDefines, ...userDefineReplacements, ...userEnvReplacements, ...builtInEnvReplacements, 'import.meta.env.': `({}).`, 'import.meta.env': JSON.stringify({ ...userClientEnv, ...builtInClientEnv }), 'process.env.NODE_ENV': JSON.stringify(resolvedMode), 'process.env.': `({}).`, 'process.env': JSON.stringify({ NODE_ENV: resolvedMode }), 'import.meta.hot': `false` }, !!sourcemap ),
就是這段程式碼轉寫了我們業務程式碼中的process.env
元凶找到,就有相應的解決方案了
方案
最老的版本的Vite,只能這樣做才可以
eval(['process',"env"].join('.'))
當前版本的Vite,這樣寫也可以的:
process["env"]
官方推薦使用的方式
import.meta.env
但我不推薦這樣用,這種寫法拿到的env物件的內容和實際的內容是有出入的。