缘起
在Electron的渲染进程中(也就是页面代码中),
我们常常使用process.env来携带一些环境变量,
比如HTTP服务地址的基质,本地静态资源的路径等
这样做主要有两个目的
一个是方便开发者写多个配置环境变量的文件,区分生产环境、测试环境和开发环境
另一个是主进程和渲染进程共享一套环境变量,全局任何一个地方都随取随用,非常方便
正因为如此,一般的编译工具都不会动用户的process对象
但Vite不一样,Vite的作者认为Vite只是给Web(运行在浏览器中的)产品提供服务的,
所以编译时把用户的process对象吃掉没关系,甚至可以拉一个完全不一样的东西给开发者都没影响
因为Web前端开发者用不到这个对象
哎,尤雨溪完全忽略了Electron开发者的感受
现象
用Vite创建一个Vue3项目,在入口文件中输出这两个对象
代码语言:javascript复制console.log(process)
console.log(process.env)
然后用Vite编译,Electron打包编译的文件,安装并启动Electron,打开调试器,
process对象的输出如下(注意process下env属性是正常的):
process.env对象的输出如下:
为什么会出现这种现象呢?我们打开Vite编译后的文件,找到目标位置,发现代码被转化成了这个样子:
代码语言:javascript复制 console.log(process);
console.log({NODE_ENV: "production"});
process还是老样子,但process.env被直接转成了一个对象字面量
原理
想来Vite这么做可能的原因是:
在process.env下加属性是Node.js开发者最常用的区分生产环境和开发环境的方案了
但浏览器环境下根本就没有process对象,那怎么办呢?
就直接粗暴的改写了开发者的代码吧
把process.env转码成了{NODE_ENV: "production"}
于是,就是现在我们看到的结果
翻翻Vite的代码,确实找到了如下逻辑(这是最新的代码,以前我看到的跟这还不一样):
代码语言:javascript复制 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,只能这样做才可以
代码语言:javascript复制eval(['process',"env"].join('.'))
当前版本的Vite,这样写也可以的:
代码语言:javascript复制process["env"]
官方推荐使用的方式
代码语言:javascript复制import.meta.env
但我不推荐这样用,这种写法拿到的env对象的内容和实际的内容是有出入的。