深入浅出Electron:原理、工程与实践
上QQ阅读APP看书,第一时间看更新

3.3 伪交叉编译

首先electron-builder是支持在A操作系统下为B操作系统生成应用程序的安装包的,但限制颇多,而且这样做的人很少,所以我不建议使用这个功能。如果开发者没有B操作系统的机器,我的建议是想办法得到一台这样的机器,再在这台机器上为B操作系统的用户生成安装包。

即使electron-builder提供了这方面的支持,但也并非使用了交叉编译的技术,详见后面的讲解。

其次electron-userland组织下有一个开源项目electron-build-service(https://github.com/electron-userland/electron-build-service)为打包工作提供了服务支持,如果开发者想把打包工作迁移到服务器端,可以考虑使用这个开源项目。

我们要重点解释的是electron-builder是如何在64位的操作系统上生成32位的安装包的(反之也是同样的原理)。

electron-builder并不会在开发者电脑上完成Electron源码的编译工作,而是根据用户的配置信息去服务器上下载Electron团队编译好的二进制资源,配置信息如下所示:

{
  win:{
    target: [
      {
        target: 'nsis',
        arch: ['ia32'],
      },
    ],
}
...
}
...
}

electron-builder下载并缓存Electron的逻辑与安装Electron依赖包时的下载和缓存逻辑不同。electron-builder下载Electron时使用的镜像环境变量为ELECTRON_BUILDER_BINARIES_MIRROR,缓存路径环境变量为ELECTRON_BUILDER_CACHE。

electron-builder判断是否存在缓存文件的逻辑代码如下所示:

export function getBin(name: string, url?: string | null, checksum?: string | null): Promise<string> {
  const cacheName = process.env.ELECTRON_BUILDER_CACHE + name;
  let promise = versionToPromise.get(cacheName);
  if (promise != null) {
    return promise
  }
  promise = doGetBin(name, url, checksum)
  versionToPromise.set(cacheName, promise)
  return promise
}

在这段代码中看到了ELECTRON_BUILDER_CACHE的身影。如果缓存目录中存在相应的文件,则versionToPromise.get方法返回相应的文件信息,否则electron-builder将调用doGetBin方法下载对应的二进制Electron文件。下载逻辑代码如下所示:

export function getBinFromUrl(name: string, version: string, checksum: string): Promise<string> {
  const dirName = '${name}-${version}'
  let url: string
  if (process.env.ELECTRON_BUILDER_BINARIES_DOWNLOAD_OVERRIDE_URL) {
    url = process.env.ELECTRON_BUILDER_BINARIES_DOWNLOAD_OVERRIDE_URL + "/" + dirName + ".7z"
  }
  else {
    const baseUrl = process.env.NPM_CONFIG_ELECTRON_BUILDER_BINARIES_MIRROR ||
      process.env.npm_config_electron_builder_binaries_mirror ||
      process.env.npm_package_config_electron_builder_binaries_mirror ||
      process.env.ELECTRON_BUILDER_BINARIES_MIRROR ||
      "https:// github.com/electron-userland/electron-builder-binaries/releases/download/"
    const middleUrl = process.env.NPM_CONFIG_ELECTRON_BUILDER_BINARIES_CUSTOM_DIR ||
      process.env.npm_config_electron_builder_binaries_custom_dir ||
      process.env.npm_package_config_electron_builder_binaries_custom_dir ||
      process.env.ELECTRON_BUILDER_BINARIES_CUSTOM_DIR ||
      dirName
    const urlSuffix = dirName + ".7z"
    url = '${baseUrl}${middleUrl}/${urlSuffix}'
  }
  return getBin(dirName, url, checksum)
}

在这段代码中看到了ELECTRON_BUILDER_BINARIES_MIRROR的身影,也就是说当开发者在64位操作系统上打32位的应用程序安装包时,electron-builder会去服务器下载32位的Electron二进制包,并把这个包的内容复制到你的win-ia32-unpacked目录下,从而完成“交叉编译”的需求。在A系统上为B系统制成安装包也使用了类似的机制。这实际上这并不是真正的交叉编译。