electron 国内代理源配置完全指南

结论

推荐大家有条件的话还是上科技,配置仓库总会因为其同步策略的时延或者各种各样的同步故障导致你使用的时候并没有那个版本的依赖,如果要用的话那就不要选最新版本,而是倒推几个版本。

即便是这样,也有可能存在恰巧有故障的可能,还是不要过于信任仓库,出了问题不要当作electron 版本bug

配置方式

我最常用的两个仓库是 阿里云华为云 (mirrors.huaweicloud.com/electron/) 了,这两者我推荐阿里云,就electron而言其同步效率比华为云好一些。

注意: 很多教程都只告诉你配置electron_mirror,然而这种方式是错误的,因为官方目前的逻辑时 各版本的存储路径是带有v前缀 的,而私服大多都是仅有版本号,如果不配置这个变量的话,你下载是会报 404、401等各种错误的,详细介绍参见 electron 配置代理的介绍 ,也可以看后面的分析过程

.npmrc

阿里云配置

.npmrc 复制代码
electron_mirror=https://npmmirror.com/mirrors/electron/
electron_custom_dir={{ version }}

华为云配置

.npmrc 复制代码
electron_mirror=https://mirrors.huaweicloud.com/electron/
electron_custom_dir={{ version }}

env

properties 复制代码
ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
ELECTRON_CUSTOM_DIR={{ version }}

分析过程

  • 本文编写时间: 2024年1月31日
  • 本文所用相关工具/依赖:
    • npm: 10.2.4
    • nodejs: v20.11.0
    • yarn: 1.22.21
    • pnpm: 8.15.1
    • electron@26.6.7

安装Electron的时候会去动态下载其运行时,而默认策略又是从Github 仓库地址 https://github.com/electron/electron/releases/download/ 下载, 我们访问不太稳定,经常容易因为网络问题无法成功,在没有科技或者仓库的情况下经常发现以下报错:

从上图分析可知,安装是在执行electron 的脚本 node install.js 时失败的,我们打开项目 .\node_modules\electron\install.js 脚本发现执行了以下逻辑:

js 复制代码
#!/usr/bin/env node

// ....
const { downloadArtifact } = require('@electron/get');
// ....
// downloads if not cached
downloadArtifact({
  version,
  artifactName: 'electron',
  force: process.env.force_no_cache === 'true',
  cacheRoot: process.env.electron_config_cache,
  checksums: process.env.electron_use_remote_checksums ? undefined : require('./checksums.json'),
  platform,
  arch
}).then(extractFile).catch(err => {
  console.error(err.stack);
  process.exit(1);
});

由于引入的时候没有指定具体的js,因此我们打开.\node_modules\@electron\get\cjs\index.js 发现执行了如下代码(别问为什么是cjs不是esm下的,我对node的导包不咋了解):

js 复制代码
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// ....
const artifact_utils_1 = require("./artifact-utils");
// ....
async function downloadArtifact(_artifactDetails) {
    // ....
    // 拼接地址
    const url = await artifact_utils_1.getArtifactRemoteURL(artifactDetails);
    const cache = new Cache_1.Cache(artifactDetails.cacheRoot);
    // ....
    return await utils_1.withTempDirectoryIn(artifactDetails.tempDirectory, async (tempFolder) => {
        const tempDownloadPath = path.resolve(tempFolder, artifact_utils_1.getArtifactFileName(artifactDetails));
        const downloader = artifactDetails.downloader || (await downloader_resolver_1.getDownloaderForSystem());
        d(`Downloading ${url} to ${tempDownloadPath} with options: ${JSON.stringify(artifactDetails.downloadOptions)}`);
        // 执行下载
        await downloader.download(url, tempDownloadPath, artifactDetails.downloadOptions);
        await validateArtifact(artifactDetails, tempDownloadPath, downloadArtifact);
        return await cache.putFileInCache(url, tempDownloadPath, fileName);
    });
}

打开 .\node_modules\@electron\get\cjs\artifact-utils.js 查看代码逻辑:

js 复制代码
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("./utils");
const BASE_URL = 'https://github.com/electron/electron/releases/download/';
const NIGHTLY_BASE_URL = 'https://github.com/electron/nightlies/releases/download/';
function getArtifactFileName(details) {
    utils_1.ensureIsTruthyString(details, 'artifactName');
    if (details.isGeneric) {
        return details.artifactName;
    }
    utils_1.ensureIsTruthyString(details, 'arch');
    utils_1.ensureIsTruthyString(details, 'platform');
    utils_1.ensureIsTruthyString(details, 'version');
    return `${[
        details.artifactName,
        details.version,
        details.platform,
        details.arch,
        ...(details.artifactSuffix ? [details.artifactSuffix] : []),
    ].join('-')}.zip`;
}
exports.getArtifactFileName = getArtifactFileName;
function mirrorVar(name, options, defaultValue) {
    // Convert camelCase to camel_case for env var reading
    const snakeName = name.replace(/([a-z])([A-Z])/g, (_, a, b) => `${a}_${b}`).toLowerCase();
    
    return (
    // 1.1 使用 npm/yarn/pnpm install 执行时,默认从`用户目录下/.npmrc`读取配置并加前缀 `npm_config_`
    //    具体配置文件可以通过给 install 加参数指定,各种包管理工具也有其生效、覆盖规则,在此不展开了
    // .npmrc
    process.env[`npm_config_electron_${name.toLowerCase()}`] ||
        process.env[`NPM_CONFIG_ELECTRON_${snakeName.toUpperCase()}`] ||
        process.env[`npm_config_electron_${snakeName}`] ||
        // 1.2 如果 .npmrc 未配置仓库 则检查 `package.json`的 脚本中有没有传递变量,由于 `electron` 运行的是 `node install.js`,自然读取不到变量,跳过
        // package.json
        process.env[`npm_package_config_electron_${name}`] ||
        process.env[`npm_package_config_electron_${snakeName.toLowerCase()}`] ||
        // env
        // 1.3 如果以上两种途径都没有配置仓库地址,此时还可以设置系统变量来解决,
        //    变量名称为`ELECTRON_MIRROR`、`ELECTRON_CUSTOM_DIR`等,设置方式根据自己的系统自行百度
        process.env[`ELECTRON_${snakeName.toUpperCase()}`] ||
        // 1.4 由于 `electron` 运行的是 `node install.js`,执行逻辑中未传递 `mirror`变量,跳过
        options[name] ||
        // 1.5 如果还是没有读取到仓库配置,则按调用方传递的默认值进行兜底处理
        defaultValue);
}
async function getArtifactRemoteURL(details) {
    const opts = details.mirrorOptions || {};
    // 1. 读取镜像仓库配置
    let base = mirrorVar('mirror', opts, BASE_URL);
    if (details.version.includes('nightly')) {
        const nightlyDeprecated = mirrorVar('nightly_mirror', opts, '');
        if (nightlyDeprecated) {
            base = nightlyDeprecated;
            console.warn(`nightly_mirror is deprecated, please use nightlyMirror`);
        }
        else {
            base = mirrorVar('nightlyMirror', opts, NIGHTLY_BASE_URL);
        }
    }
    // 2. 读取版本分级路径
    const path = mirrorVar('customDir', opts, details.version).replace('{{ version }}', details.version.replace(/^v/, ''));
    // 3. 读取依赖包名称
    const file = mirrorVar('customFilename', opts, getArtifactFileName(details));
    // Allow customized download URL resolution.
    if (opts.resolveAssetURL) {
        const url = await opts.resolveAssetURL(details);
        return url;
    }
    // 4. 拼接完整地址
    return `${base}${path}/${file}`;
}

上述分析过程基于 yarn install --prefer-offline 进行 debug

延伸学习

node 技术栈读取/配置环境变量的方式有以下几种,

纯 node

使用 node --env-file=.env test.js 传递,

.env 配置文件格式为:

KEY=VALUE

package.json

在不使用框架的情况下, 一个基础的 node项目也可以通过在配置命令的时候传递变量 或者 变量文件使用,即:package.jsonscripts 节点:

js 复制代码
  "scripts": {
    # 需要安装依赖 cross-env,此方式未验证
    "dev": "cross-env KEY1=VALUE1 node test.js",
    "test": "node --env-file=.env test.js"
  }

本例的 electron 下载运行时并不适用,这个方式仅用于给项目本身配置变量

环境变量

可以当前shell 或者修改配置文件,仅举例

ini 复制代码
# windows  powershell
$env:AA=1
# linux
export AA=1

others

在使用vue-cli 或者 vite等其它工具时,该框架一般也会有自己的变量配置和读取规则,例如 vue-cli会要求你的 .env配置文件 变量基本要以 VUE_APP_作为前缀才能读取(参考链接(模式和环境变量 | Vue CLI (vuejs.org))

相关推荐
Lei_zhen962 小时前
记录一次electron-builder报错ENOENT: no such file or directory, rename xxxx的问题
前端·javascript·electron
辣条小哥哥2 小时前
electron主进程和渲染进程之间的通信
javascript·electron·ecmascript
咖喱鱼蛋2 小时前
Electron一些概念理解
前端·javascript·electron
sun lover1 天前
electron快速上手
javascript·electron
Jornici3 天前
搭建vue-electron项目
前端·vue.js·electron
横冲直撞de4 天前
electron客户端预览doc、docx、excel、pdf、ppt、csv、txt等文件类型
electron·pdf·excel
我也有在努力4 天前
解决Electron拖拽窗口点击事件失效问题
前端·javascript·vue.js·typescript·electron·vue
怕冷的火焰(~杰)5 天前
Electron: 主进程和渲染进程之间通信
electron
怕冷的火焰(~杰)5 天前
自定义菜单栏实现点击添加按钮打开渲染进程的Dialog.vue模态框
electron
A黄俊辉A7 天前
electron安装遇到的问题
前端·javascript·electron