緣起
在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對象的內容和實際的內容是有出入的。