记录macOS下由yarn与npm差异引发的Electron镜像地址读取问题

写在前面:该问题仅仅出现在Linux和macOS上,Windows上不存在该问题!

初始背景

最近笔者重新拾起了Electron,把最新版Electron的官方文档阅读了一遍。众所周知,Electron作为依赖在安装的时候,其二进制文件下载在国内一直以来都是问题(因为默认会从github上下载),好在现在Electron的官方文档已经写的非常详细了:安装指导 | Electron (electronjs.org),只需要配置一个镜像地址到.npmrc中:

ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"

记住这个大写的Key

笔者由于是新的机器,还没有配置改值,所以找到.npmrc文件的配置了上述的镜像后,便开开心心的准备进行项目搭建了。

问题出现

然而,当笔者准备使用yarn执行如下命令的时候,却出了问题:

yarn add -D electron

运行启动以后,在Electron安装的环境一直卡住了很久很久。

咦,难道镜像配置写错了吗?仔细对比以后,没有问题。难道因为我的网络访问很慢吗?等到访问超时以后,发现一个IP地址超时了,心想国内镜像再怎么也不应该超时,盲猜镜像地址没有生效。于是乎,准备尝试对下载Electron二进制文件的过程进行debug。

问题排查

首先定位到node_module/electron包,能够看到有一段安装后脚本执行命令(postinstall):

关于postinstall的详细说明:scripts | npm Docs (npmjs.com)

也就是说,node_module/electron本身npm包install完成以后,还会执行其包内的install.js。

定位进入了node_module/electron包下的install.js,该脚本内部主要逻辑是先检查Electron的二进制缓存,如果不存在缓存,则使用来自@electron/get包中提供的downloadArtifact方法从远端下载Electron二进制制品文件。

我们暂时先不看缓存读写的逻辑,着重了解远端下载的逻辑,所以我们进入@electron/get包中的downloadArtifact

查看@electron/get包下的index.js内容:

前面我们提到,怀疑镜像地址没有生效导致下载超时,所以我们重点关注一下这里通过getArtifactRemoteURL方法得到的url值,

由于每一次这个包都会重新安装,我们不太好调试这个值,所以,我们做一个简单的trick:

  1. 找到这个包的缓存(macOS上的路径为:~/Library/Caches/Yarn/v6/npm-@electron-get-xxxx):

  1. 找到上述indexjs代码,并添加一段日志打印:

  1. 准备完毕以后,我们重新在demo项目下执行yarn add -D electron。执行以后,等到超时以后,发现控制台日志打印如下:

Why!?为什么这个下载的Electron二进制文件地址依然是github的?于是,我们有必要进一步查看这个URL是如何得到。

继续查看代码,这个url来源于artifact-utils中的getArtifactRemoteURL方法,而这个方法里面关于最终返回的url最重要的部分是下图所示的base的值:

而这个base值来源于mirrorVar这个方法:

根据上面代码的逻辑,name值为"mirror",options未使用,defaultValue为:

"https://github.com/electron/electron/releases/download/"

也就是说,在后面的逻辑中,如果没有从process.env中找到对应的值,那么就会使用默认的github官方制品地址的值。按照代码逻辑,运行到这个方法的时候,会从process.env中尝试获取:

  1. "NPM_CONFIG_ELECTRON_MIRROR"
  2. "npm_config_electron_mirror"
  3. "npm_package_config_electron_mirror"
  4. "ELECTRON_MIRROR"

环境变量—— 配置 | npm 中文网 (nodejs.cn)

任何以 npm_config_ 开头的环境变量都将被解释为配置参数。 例如,将 npm_config_foo=bar 放入您的环境中会将 foo 配置参数设置为 bar。 任何未赋值的环境配置都将被赋值为 true。 配置值不区分大小写,因此 NPM_CONFIG_FOO=bar 的工作方式相同。 但是,请注意,在 scripts 内部,npm 将设置自己的环境变量,并且 Node 会更喜欢那些小写版本,而不是您可能设置的任何大写版本。 详情见此问题

请注意,您需要使用下划线而不是破折号,因此 --allow-same-version 将变为 npm_config_allow_same_version=true

此外,如果是配置在npmrc里面的配置,也会在npm/yarn启动的时候被作为环境变量放到process.env中被访问。

那我们在.npmrc中配置的ELECTRON_MIRROR,在process.env中变成了什么呢?通过添加日志打印,我们会看到:

可以看到,在process.env中,这个键为"npm_config_ELECTRON_MIRROR"npm_config小写,ELECTORN_MIRROR大写)。我们知道,nodejs中object对象的属性值是大小写敏感的!所以,当上面的mirrorVar代码运行,尝试获取process.env中的值的时候,根本找不到了,因为没有"NPM_CONFIG_ELECTRON_MIRROR""npm_config_electron_mirror""npm_package_config_electron_mirror""ELECTRON_MIRROR"这些属性。

然而,如果我们使用npm进行安装的时候:

npm install -D electron

又能够很快安装。Why?!难道npm和yarn下的运行环境有差异吗?为了验证,我们编写一个简单的index.js代码:

console.log("process.env['npm_config_electron_mirror']", process.env['npm_config_electron_mirror']);
console.log("process.env['NPM_CONFIG_ELECTRON_MIRROR']", process.env['NPM_CONFIG_ELECTRON_MIRROR']);
console.log("process.env['npm_config_ELECTRON_MIRROR']", process.env['npm_config_ELECTRON_MIRROR']);

然后,在package.json中添加脚本:

{
"name": "simple-electron-main-app",
"version": "1.0.0",
"scripts": {
+ "start": "node index.js"
},
"devDependencies": {}
}

最后,我们分别使用yarn(yarn start)和npm(npm run start)来运行脚本:

在yarn运行上下文中,.npmrc中的"ELECTRON_MIRROR"直接拼接到了"npm_config_"后边,作为process.env的一个属性,所以你只能访问process.env["npm_config_ELECTRON_MIRROR"]得到值;

在npm运行山下文中,.npmrc中的"ELECTRON_MIRROR"首先被转为了小写,然后拼接到了"npm_config_"后边,作为了process.env的属性,所以你需要访问process.env["npm_config_electron_mirror"]来得到值。

macOS解决方式

终于,我们能解释为什么当我们在.npmrc配置大写的ELECTRON_MIRROR的时候,使用yarn add -D electron安装electron的时候,二进制镜像地址没有生效了。那么,解决的办法也非常简单,两种:

  1. .npmrc配置改为小写key:electron_mirror="https://npmmirror.com/mirrors/electron/"
  2. 使用npm上下文环境进行安装。

个人更加建议按照第一种方式配置,不然大小写敏感的坑太容易发生了。

关于Windows的特别说明

process.env | Node.js API 文档 (nodejs.cn)

在 Windows 操作系统上,环境变量不区分大小写。

const { env } = require('node:process');

env.TEST = 1;
console.log(env.test);
// => 1

也就是说,在Windows机器上,即使process.env中的key为"npm_config_ELECTRON_MIRROR",你也可以通过"npm_config_electron_mirror"或者是"NPM_CONFIG_ELECTRON_MIRROR"来访问这个值:

macOS下由yarn与npm差异引发的Electron镜像地址读取问题的更多相关文章

  1. macOS下利用dSYM文件将crash文件中的内存地址转换为可读符号

    一.使用流程 Windows下的程序运行崩溃时,往往可以利用pdb文件快速解析出程序崩溃的具体位置,甚至可以对应到源代码的具体行数.macOS下的symbolicatecrash也具备相应的功能.对应 ...

  2. npm设置为淘宝镜像地址

    1. npm设置为淘宝镜像 $npm config set registry https://registry.npm.taobao.org 2. 检查一下 $npm config get regis ...

  3. npm 更改在线仓库镜像地址

    node 安装后,npm 的默认在线仓库镜像地址为: https://registry.npmjs.org/ 使用 npm get registry 命令可以获取到: 为了使用 npm 能够更快的下载 ...

  4. Yarn vs npm: 你需要知道的一切

    Yarn 是 Facebook, Google, Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具.就像我们可以从官方文档了解那样,它的目的是解决这些团队使用 npm ...

  5. Yarn vs npm: 你需要知道的一切(转)

    英文原文:https://www.sitepoint.com/yarn-vs-npm/ 译文:http://web.jobbole.com/88459/ Yarn 是 Facebook, Google ...

  6. [web前端] yarn和npm命令使用

    原文地址: https://blog.csdn.net/mjzhang1993/article/details/70092902/ 最初接触 yarn 还是在 0.17.10 版本,由于各种各样的原因 ...

  7. Yarn vs npm:你需要知道的一切(转)

    转载:https://zhuanlan.zhihu.com/p/23493436 原文链接:Yarn vs npm: Everything You Need to Know Facebook.Goog ...

  8. node的包管理工具:yarn和npm

    arn是Facebook发布的一款依赖管理工具,它比npm更快.更高效. NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题. 一.yarn官方网站: 英文官网:ht ...

  9. 了解 yarn 、npm、nodejs

    一.前言 针对即将上线的 jeecg-boot 做一些准备.   二.了解系列 1.了解 nodejs Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrom ...

  10. 解决Homestead yarn , npm run dev, 命令报错问题!

    解决Homestead yarn , npm run dev, 命令报错问题! 2018年06月01日 11:50:51 偶尔发发颠 阅读数:1654    版权声明:本文为博主原创,未经博主同意,不 ...

随机推荐

  1. 在jsp页面int和String类型的相互转换

    浅浅地来做一个对比吧! .java文件 int转成string类型:String s=String.valueOf(int m); String转成int类型:int m=Integer.parseI ...

  2. CSharp linq 的本质

    linq 的本质是扩展方法和委托的结合 链式 linq 和 方法级linq List<int> list = new List<int>() { 3,9,32,7 }; // ...

  3. Teamcenter_NX集成开发:通过NXOpen查询零组件是否存在

    之前用过NXOpen PDM的命名空间下的类,现在记录一下通过PDM命名空间下的类查询Teamcenter零组件的信息,也可以用来判断该零组件是否存在. 1-该工程为DLL工程,直接在NX界面调用,所 ...

  4. 微信-JSSDK网页调用-(微信扫一扫)

    网页调用微信扫一扫接口 1.准备工作:  1.1微信浏览器 1.2微信APPID,nonceStr 2.使用方式快速预览 调用扫一扫微信接口. 1需要获取access_token 2获取 $jsapi ...

  5. webpack踩坑日记

    webpack 4.x 详细入门这是一个大佬的总结,但是我用webpack5重写该demo时,发现了几个有问题的地方1:CleanWebpackPlugin 应该这样: const { CleanWe ...

  6. [CTF]picoCTF-day1

    Lets Warm Up If I told you a word started with 0x70 in hexadecimal, what would it start with in ASCI ...

  7. .net core基于HttpClient实现的网络请求库

    Soda.Http 基于HttpClient封装的 Http 请求库.如果有什么好想法,可以提 Issue 或者 Pr.,如果想要使用,直接在nuget搜索Soda.Http即可. Github项目地 ...

  8. java -- Stringbuild, Date, Calendar

    Stringbuild类 由于String类的对象内容不可改变,每次拼接都会构建一个新的String对象,既耗时,又浪费内存空间 这时需要通过java提供的StringBuild类解决这个问题 Str ...

  9. ARM 详解

    一.ARM 的发展史 ARM 的发展历史可以追溯到 1978 年,当年克里斯·库里(Chris Currry)所任职的公司遭遇财务危机,发展每况愈下,库里在和创始人深入沟通后,决定离职.当时的库里对微 ...

  10. PDD也可以通过ID获取商品详情?

    先我们可以通过pinduoduo.item_get的接口传入商品的ID参数,这个接口可以获取到拼多多商品的详情数据,包括商品的标题.价格.原价.卖家的昵称.库存.销量.宝贝的链接.商品的备注.宝贝图片 ...