1.3 镜像策略
install.js脚本下载Electron可执行文件及其二进制资源的入口方法的代码如下所示:
downloadArtifact({ version, artifactName: 'electron', force: process.env.force_no_cache === 'true', cacheRoot: process.env.electron_config_cache, platform: process.env.npm_config_platform || process.platform, arch: process.env.npm_config_arch || process.arch }).then(extractFile).catch(err => { console.error(err.stack) process.exit(1) })
这个downloadArtifact方法并不是Electron包内的脚本提供的方法,而是另一个包@electron/get提供的方法。开发者可能会有疑惑:我并没有安装@electron/get包,它是从哪来的呢?
因为@electron/get包是Electron包依赖的一个npm包,npm工具在安装Electron包时,发现它依赖了@electron/get包,所以就把它安装到你的项目中了。这实际上是一个递归的过程,@electron/get包依赖的其他npm包也会被npm工具安装到你的项目中。
拓展:在npm 3.x以前,npm的包管理方式是嵌套结构的,也就是说一个工程安装的依赖包位于当前工程根目录下的node_modules目录中,假设其中一个依赖包又依赖了其他npm包,我们假设这个依赖包叫作packageA,那么它的依赖包会被安装在packageA目录的node_modules目录下,依此类推。
以这种方式管理依赖包会导致目录层级很深。在Windows操作系统中,文件路径最大长度为260个字符,目录层级过深会导致依赖包安装不成功。不同层级的依赖中可能引用同一个依赖包,这种结构也没办法复用这个依赖包,会造成大量的冗余、浪费。
自npm 3.x以来,npm的包管理方式升级为了扁平结构,无论是当前工程的依赖包还是依赖包的依赖包,都会被优先安装到当前工程的node_modules目录下,在安装过程中如果npm发现当前工程的node_modules目录下已经存在了相同版本的某个依赖包,那么就会跳过安装过程,直接让工程使用这个已安装的依赖包。只有在版本不同的情况下,才会在这个包的node_modules目录下安装新的依赖包。
这就很好地解决了前面两个问题,但也引来了新的问题,直到npm 5.x引入了package lock的机制后,新的问题才得以解决。对详情感兴趣的读者可参阅https://docs.npmjs.com/configuring-npm/package-lock-json.html。另外,npm判断两个依赖包是否版本相同,是有一套复杂的规则的,详见https://docs.npmjs.com/about-semantic-versioning。
包如其名,@electron/get包存在的意义就是下载Electron可执行文件及其二进制资源。
从前面的代码已经知道,downloadArtifact方法的入参是一个JSON对象。
对象的force属性标记着是否需要强制下载Electron的二进制文件,如果环境变量force_no_cache的值为true,则无论本地有没有缓存,都会从Electron的服务器下载相应的文件。
对象的version属性是需要下载的Electron可执行程序的版本号,这个版本号就是定义在Electron包内package.json文件中的版本号。
对象的platform属性是开发者当前操作系统的名称,process.platform得到的结果可能是darwin(Mac操作系统)、win32(64位的Windows操作系统也是返回win32)或linux,与require('os').platform()得到的结果是相同的。也就是说install.js脚本会根据用户当前的操作系统来下载不同的Electron可执行文件。这一点后面还会有介绍。
对象的arch属性是开发者当前操作系统的架构,可能的值为x32或x64。这些信息都是帮开发者确定下载什么版本的Electron可执行文件的。
上述信息最终会被组装成的下载地址可能是如下的样子(其中版本号视真实情况而定):
https:// github.com/electron/electron/releases/download/v13.1.6/electron-v13.1.6-win32-x64.zip
@electron/get包把这个地址分成了三个部分。
- 镜像部分:https://github.com/electron/electron/releases/download/。
- 版本部分:v13.1.6/。
- 文件部分:electron-v13.1.6-win32-x64.zip。
这三部分联合起来最终构成了下载地址,每个部分都有其默认值,也有对应的重写该部分值的环境变量。
- 镜像部分的环境变量:ELECTRON_MIRROR。
- 版本部分的环境变量:ELECTRON_CUSTOM_DIR。
- 文件部分的环境变量:ELECTRON_CUSTOM_FILENAME。
一般情况下,我们只需要设置镜像部分的环境变量即可,比如把ELECTRON_MIRROR的环境变量的值设置为https://npm.taobao.org/mirrors/electron/,这是阿里巴巴团队为国内开发者提供的镜像地址。如果你的公司禁用了*.taobao.org,可以使用华为团队提供的镜像服务:https://mirrors.huaweicloud.com/electron/。
为Windows操作系统设置环境变量的方法如图1-1所示。
图1-1 设置系统环境变量
需要注意的是,刚刚更新的版本可能并不会及时地同步到镜像服务中,需耐心等待一段时间(一般不会超过一天),镜像服务才会同步完成。
Electron的可执行文件及其依赖的二进制资源被存放在一个压缩包中,这个压缩包的名字就像electron-v13.1.6-win32-x64.zip这样。除了下载这个压缩文件外,downloadArtifact还单独下载了一个SHASUMS256.txt文件,这个文件内记录了Electron二进制文件压缩包的sha256值,程序会对比一下这个值与压缩包文件的sha256值是否匹配,这样做的目的有两个:
- 避免用户请求被截获,下载到不安全的文件(这方面的效用只能说聊胜于无)。
- 避免下载过程意外终止,下载到的文件不完整。
所以这就是解决方案之一:通过设置镜像服务来解决无法安装Electron依赖包的问题。当然还有其他解决方案,下面我们就通过介绍Electron依赖包的缓存策略来介绍第二种方案。