macOS下由yarn与npm差异引发的Electron镜像地址读取问题
记录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:
- 找到这个包的缓存(macOS上的路径为:
~/Library/Caches/Yarn/v6/npm-@electron-get-xxxx
):
- 找到上述indexjs代码,并添加一段日志打印:
- 准备完毕以后,我们重新在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
中尝试获取:
- "NPM_CONFIG_ELECTRON_MIRROR"
- "npm_config_electron_mirror"
- "npm_package_config_electron_mirror"
- "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的时候,二进制镜像地址没有生效了。那么,解决的办法也非常简单,两种:
.npmrc
配置改为小写key:electron_mirror="https://npmmirror.com/mirrors/electron/"
;- 使用
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镜像地址读取问题的更多相关文章
- macOS下利用dSYM文件将crash文件中的内存地址转换为可读符号
一.使用流程 Windows下的程序运行崩溃时,往往可以利用pdb文件快速解析出程序崩溃的具体位置,甚至可以对应到源代码的具体行数.macOS下的symbolicatecrash也具备相应的功能.对应 ...
- npm设置为淘宝镜像地址
1. npm设置为淘宝镜像 $npm config set registry https://registry.npm.taobao.org 2. 检查一下 $npm config get regis ...
- npm 更改在线仓库镜像地址
node 安装后,npm 的默认在线仓库镜像地址为: https://registry.npmjs.org/ 使用 npm get registry 命令可以获取到: 为了使用 npm 能够更快的下载 ...
- Yarn vs npm: 你需要知道的一切
Yarn 是 Facebook, Google, Exponent 和 Tilde 开发的一款新的 JavaScript 包管理工具.就像我们可以从官方文档了解那样,它的目的是解决这些团队使用 npm ...
- Yarn vs npm: 你需要知道的一切(转)
英文原文:https://www.sitepoint.com/yarn-vs-npm/ 译文:http://web.jobbole.com/88459/ Yarn 是 Facebook, Google ...
- [web前端] yarn和npm命令使用
原文地址: https://blog.csdn.net/mjzhang1993/article/details/70092902/ 最初接触 yarn 还是在 0.17.10 版本,由于各种各样的原因 ...
- Yarn vs npm:你需要知道的一切(转)
转载:https://zhuanlan.zhihu.com/p/23493436 原文链接:Yarn vs npm: Everything You Need to Know Facebook.Goog ...
- node的包管理工具:yarn和npm
arn是Facebook发布的一款依赖管理工具,它比npm更快.更高效. NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题. 一.yarn官方网站: 英文官网:ht ...
- 了解 yarn 、npm、nodejs
一.前言 针对即将上线的 jeecg-boot 做一些准备. 二.了解系列 1.了解 nodejs Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrom ...
- 解决Homestead yarn , npm run dev, 命令报错问题!
解决Homestead yarn , npm run dev, 命令报错问题! 2018年06月01日 11:50:51 偶尔发发颠 阅读数:1654 版权声明:本文为博主原创,未经博主同意,不 ...
随机推荐
- MySQL学习(二)事务的隔离级别
:规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的.较低级别的隔离通常可以执行更高的并发,系统的开销也更低 read uncommitted(未提交读):事务中的修改,即使没有 ...
- java网络编程--5 URL 下载网络资源
java网络编程--5 URL 下载网络资源 1.8.URL 统一资源定位符,定位互联网的某一个资源 DNS域名解析 www.baidu.com -->xxx.xxx.xxx.xxx // 协议 ...
- SpringBoot——静态资源及原理
一.使用 SpringBoot 的步骤 [1]创建 SpringBoot应用,选中自己需要的模块.[2]SpringBoot 已经默认将这些场景配置好,只需要在配置文件中指定少量配置就可以运行起来.[ ...
- Python 中 is 和 == 的区别
is 和 == 的区别 相信学过 Python 小伙伴们都知道 is 和 == 都是用来比较 Python 对象的,但是区别就是 is 比较需要对象的值和内存地址都相等 == 比较只需要对象的值相等就 ...
- AIGC时代:未来已来
摘要:人工智能的快速发展使得我们进入了AIGC时代.AIGC时代的到来,将会带来巨大的机遇和挑战. 本文分享自华为云社区<GPT-4发布,AIGC时代的多模态还能走多远?系列之一: AIGC时代 ...
- THM-被动侦察和主动侦查
被动与主动侦察 在计算机系统和网络出现之前,孙子兵法在孙子兵法中教导说:"知己知彼,必胜不疑." 如果您扮演攻击者的角色,则需要收集有关目标系统的信息.如果你扮演防御者的角色,你需 ...
- vue之列表渲染v-for
目录 简介 用法 v-for可循环的几种变量的展示 数组的循环展示 对象的循环展示 字符串的循环展示 数字的循环展示 v-for搭档key值的说明 js循环几种方式 基于索引的循环 数组的循环 数组基 ...
- sqlite4操作
目录 SQLite数据库(一):基本操作... 1 目录... 1 一.SQLite介绍... 2 1. 什么是SQLite. 2 2. 什么是数据库... 2 3. 数据库是如何存 ...
- 用 Go 剑指 Offer 11. 旋转数组的最小数字
已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组.例如,原数组 nums = [0,1,4,4,5,6,7] 在变化后可能得到:若旋转 4 次,则可以得到 [ ...
- [Java EE]缓存技术初探
1 背景 使用场景:计算或检索一个值的代价很高,并且对同样的输入需要不止一次获取值的时候,就应当考虑使用缓存. 高并发下,为提高 频繁 查询 大量 可能常用的 数据库数据的 查询效率. 大部分情况下, ...