前言
在 基本项目搭建 中,我们已经能够启动一个 electron 应用程序了(开发环境),现在来看如何将之打包为二进制程序便于分发给最终用户。
依赖
- electron-builder: 打包的主要工具库,负责这个 electron 的跨平台打包工作
事实上,还有一些其它的打包工具,但目前还没有比它更好的,参考: https://npmcompare.com/compare/electron-builder,electron-forge,electron-packager
渲染层打包
直接使用 cra 的打包工具即可,没什么大不了的,但确实存在一些注意事项
- 因为 electron 在生产环境会从文件系统中加载静态资源,所以打包出来的静态资源必须支持相对路径,下面是常见的两个设置。
- 必须在 apps/renderer/package.json 中声明
"homepage": "."
,参考: Building for Relative Paths - 路由必须是
hash
模式
- 必须在 apps/renderer/package.json 中声明
主进程打包
electron-builder 打包需要以下几个步骤
更新 package.json 的一些配置
- 使用 package.json 中的
build
字段作为配置项,参考: https://www.electron.build/ - electron-builder 使用
main
字段作为启动脚本文件 - electron-builder 要求必须使用固定的版本号,意味着 electron 依赖需要指定为
"electron": "10.2.0"
下面是一个基本的配置示例
{
"main": "dist/main.js",
"scripts": {
// 一个非常基本的打包脚本
"pkg": "electron-builder"
},
"devDependencies": {
"electron": "10.2.0",
"electron-builder": "^22.9.1",
// electron 主进程实际上是 nodejs 环境,所以为了更好的开发体验,安装 nodejs 的类型定义
"@types/node": "^12.19.12"
},
"build": {
// 程序的唯一标识符
"appId": "com.rxliuli.electron_example",
// 打包出来的 exe 名字
"productName": "electron 示例应用",
// 打包的目录
"directories": {
"output": "release"
},
"win": {
// 打包目标,参考: https://www.electron.build/
"target": ["nsis"]
}
}
}
复制静态资源
现在,我们需要打包静态资源并复制到主进程模块里面
cd apps/renderer
目录yarn build
打包静态资源- 将静态资源复制到
build/dist
目录下
修改主进程入口文件 main.ts
还需要修改 src/main.ts 代码,主要修改 BrowserWindow 对象载入的 url
地址
import { app, BrowserWindow } from 'electron'
import path = require('path')
import { URL } from 'url'
async function createMainWindow() {
// 创建新的 electron 窗口
const mainWindow = new BrowserWindow()
// 载入生产环境的 url
await mainWindow.loadURL(
new URL(path.join(__dirname, './build/index.html')).href,
)
}
// 其他代码...
注意,这个 url 路径是相对于打包后的
dist/main.js
而言的,因为最终打包的程序运行时的相对路径也是这样。
打包主进程的 exe 程序
因为 electron-builder 需要下载基本的 electron 程序,所以请提前设置好透明代理,如果不知道它是什么,参考: 透明网关,Proxifier
- 使用
yarn compile
编译 ts 代码 - 使用
yarn pkg
打包 electron 应用
现在,我们应该可以在 apps/main/release/win-unpacked 下看到 exe 程序,双击它即可看到之前在开发环境的首页了。
参考: https://github.com/rxliuli/electron_example/tree/85d398fc2c6ba6c918ad9641dbb5d8bae2d4216b/apps/main
优化打包
虽然打包已经实现,但确实还存在一些问题
- 打包脚本仍然不是一键的
- 不能兼容开发、生产环境
下面我们来解决这两个问题
实现一键打包二进制程序
使用 gulp 复制渲染层的静态资源
1、添加 gulp 相关依赖 yarn add -D gulp ts-node @types/gulp fs-extra @types/fs-extra
gulp @types/gulp
: gulp 核心依赖ts-node
: 使用 ts 编写 gulp 脚本必须的依赖fs-extra @types/fs-extra
: fs 的扩展增强,使用 Promise 包装异步 api
2、添加 gulp 脚本文件
import { copy, remove } from 'fs-extra'
import * as path from 'path'
async function copyByMap(copyMap: [string, string][]) {
await Promise.all(
copyMap.map(async ([src, destDir]) => {
const srcPath = path.resolve(__dirname, src)
const destPath = path.resolve(__dirname, destDir, path.basename(srcPath))
await copy(srcPath, destPath)
}),
)
}
/**
* 清理最终生成目录
*/
export async function clean() {
await remove(path.resolve(__dirname, 'dist'))
await remove(path.resolve(__dirname, 'release'))
}
/**
* 复制一些资源到 dist 目录中
*/
export async function copyStatic() {
await copyByMap([['../renderer/build', 'dist/']])
}
3、添加 npm script
注: lerna 的好处之一就是可以运行其它模块的 npm script。
{
"scripts": {
// 打包渲染层的静态资源
"build:web": "lerna run --scope renderer build",
// 打包渲染层的静态资源之后复制然后使用 electron-builder 打包 exe 程序
"pkg": "gulp clean && yarn compile && yarn build:web && gulp copyStatic && electron-builder"
}
}
4、修改 tsconfig.json
此时在 apps/main 模块根目录下也有 ts 文件了,所以 tsc 翻译代码会将它们也包含进去,但实际上不需要。
{
"include": ["src"]
}
现在,我们可以使用一个命令打包 exe 程序了。
参考: https://github.com/rxliuli/electron_example/blob/3dacff5dc0/apps/main/package.json
使用环境变量来兼容开发、生产环境
解决方案简单来说就一句话:使用环境变量指定开发环境的 URL。 这里使用 env-cmd 来跨平台写入环境变量(不使用 dotenv 的原因在于自定义环境使用起来有点麻烦,不像 env-cmd 那么直观),而另一个 cross-env 并未提供管理环境变量的解决方案。下面说一下使用 env-cmd 的步骤
安装依赖
yarn add -D env-cmd
添加配置文件 .env-cmdrc.json 基本上是一个键值映射文件,键是环境,值对象是环境变量
{ "dev": { "ELECTRON_START_URL": "http://localhost:3000/" } }
在
dev:electron
命令之前设定环境变量env-cmd -e dev electron ./dist/main.js
修改 src/main.ts 读取环境变量
await mainWindow.loadURL( process.env.ELECTRON_START_URL || path.join(__dirname, './build/index.html'), )
现在,像 基本项目搭建 中 更新 package.json 添加几个 npm script 说的那样启动开发环境就会显示开发环境的页面,打包后显示的则是打包后的静态资源。
参考: https://github.com/rxliuli/electron_example/blob/f8b4f94435/apps/main/.env-cmdrc.json
总结
虽然 electron-builder 已经足够好用了,但它仍然不能解决 electron 项目工程上的问题,所以这里结合了 lerna/gulp/env-cmd
打包。