创建于 2019.10.27
## 背景
今天想重新摸一下 electron 做个带 web-server 的小 demo,所以就搭了一个 electron 的项目,执行
yarn add electron --exact命令的时候时间很长,但是并没有报错,但是在后续执行yarn electron的时候,报错说我的 electron 没有安装成功,需要重新安装。我按提示删除了node_modules/electron文件夹再执行 electron 的安装命令,重复几次以后,我通过yarn --force --verbose去看了详细的 log,应该就是网络问题,所以导致下载失败,因为 electron 的默认下载链接 BASE_URL是托管在 github 上,国内访问 github 基本是几十 kb,所以一定会挂。
经过一番 google,发现 Electron 官网有提到可以通过ELECTRON_MIRROR来指定自己的 electron 下载镜像站,并且直接提到可以通过以下的方式来指定淘宝 Electron 镜像。
ELECTRON_MIRROR="https://npm.taobao.org/mirrors/electron/" yarn add electron但是在使用上述指令安装时,还是没有报错,但是也没有成功,于是继续用
--verbose来看是什么原因没有成功,发现这次的报错变成了 404 not found,这就是说这个ELECTRON_MIRROR环境变量是有用的。于是我们开始看源码 electron 的安装到底做了些啥。
## 分析原因
1. electron 的 npm 包进行指定了
"postinstall": "node install.js"2. 两个判断会退出下载,设置
ELECTRON_SKIP_BINARY_DOWNLOAD的环境变量,或是安装的 version 还没安过(dist 目录里没有这个文件)if (process.env.ELECTRON_SKIP_BINARY_DOWNLOAD) {
process.exit(0);
}
const platformPath = getPlatformPath();
const electronPath = process.env.ELECTRON_OVERRIDE_DIST_PATH || path.join(__dirname, 'dist', platformPath);
if (installedVersion === version && fs.existsSync(electronPath)) {
process.exit(0);
}3. 使用
@electron/get(1.6.0)包的downloadArtifact函数进行下载,下载后解压4. 然后找到拼接 url 的地方,是一个叫
getArtifactRemoteURL的函数,他会用 details.version 作为默认值,然后通过customDir的环境变量来覆盖写const path = mirrorVar('customDir', opts, details.version);
const url = `${base}${path}/${file}`;5. 发现 version 这里有问题,他会把所有的 version 前面加上 v,但是淘宝镜像的路径是没有 v 的,所以才会拼出来 404,万幸的是后面的 file 拼接是没有问题的,所以我们只需要对
customDir做一个指定就行了。artifactDetails.version = normalizeVersion(artifactDetails.version);
export function normalizeVersion(version: string) {
if (!version.startsWith('v')) {
return `v${version}`;
}
return version;
}## 解决方案
由于我现在用的是 7.0.0 版本,所以手动执行一下
ELECTRON_MIRROR=https://npm.taobao.org/mirrors/electron/ ELECTRON_CUSTOM_DIR=7.0.0 yarn --force --verbose也可以在.npmrc 里面配置
electron-mirror=https://npm.taobao.org/mirrors/electron/
electron-custom-dir=7.0.0还可以通过一些方式来指定吧,以下是 mirrorVar 函数的源码
function mirrorVar(name: keyof MirrorOptions, options: MirrorOptions, defaultValue: string) {
// Convert camelCase to camel_case for env var reading
const lowerName = name.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}_${b}`).toLowerCase();
return (
process.env[`NPM_CONFIG_ELECTRON_${lowerName.toUpperCase()}`] ||
process.env[`npm_config_electron_${lowerName}`] ||
process.env[`npm_package_config_electron_${lowerName}`] ||
process.env[`ELECTRON_${lowerName.toUpperCase()}`] ||
options[name] ||
defaultValue
);}## 注意
需要注意这里的版本要手动指定,所以最好使用 exact 版本,防止
^或*semver 用了小版本或 patch 版,所以下载错了二进制文件了造成一些疑惑。