Electron 脚手架推荐
前言
官方是有个 forge 的脚手架,但是文档还不够全面,目前推荐使用 erb:electron-react-boilerplate/electron-react-boilerplate: A Foundation for Scalable Cross-Platform Apps
双层 package.json
这是 electron-builder 约定的, Two package.json Structure - electron-builder, 但是让人很困惑: Confused by 2 package.json structure · Issue #600 · electron-userland/electron-builder, erb 给的说法还是挺直接的,Adding Dependencies | Electron React Boilerplate:
- 优先安装在最外层的
package.json
的dependencies
- 除了 native modules, or modules with native dependencies or peer dependencies. Native modules, or packages with native dependencies, 这些应该放在内层的
package.json
中 - 编译,测试等, 都放在最外层
package.json
的devDependenciese
什么时候 rebuild ?
所有的 dependences
包, 优先还是在最外层安装, erb 会调用 postinstall
脚本去检测是否是 native dependencies
, 如果是的话, 会提示:
should be installed inside of the "./release/app" folder.
First, uninstall the packages from "./package.json":
Then, instead of installing the package to the root "./package.json", install the package to "./release/app/package.json"
- 检测的逻辑是: 一些 native 模块,比如
node-sass
, 包目录下会包含binding.gyp
文件,check-native-dep.js
脚本能探测出来。 - 在
release/app/package.json
中定义的dependence
, 是会触发postinstall
脚本:执行npm run rebuild && npm run link-modules
内层 package.json 编译的逻辑是怎么样的?
native dependencies 是被主进程使用的,所以不是所有的包,都能放在内层 package.json
中。
- 首先需要重新编译的模块,在成功安装后, 先执行
npm run rebuild
, 触发electron-rebuild
。 - 然后触发
npm run link-modules
, 把内存编译好的模块,链接到外层的src/node_modules
目录中, src 下的代码, 就能找到对应的包了 - 整体项目构建的时候,
webpack.base.ts
中会把内层的app/package.json
的dependencies
作为构建的externals
, 期待外部注入。 - 构建后的
native dependencies
, 会被放在release/app/node_modules
目录下,也就是 erb 打包生成的目标目录, 最终会被electron-builder
打包进去。指定了directories.app
为release/app
。 - 最终被压缩到
app.asar
中, 包含的文件,是被配置在了build.files
中。 - electron renderer 是支持 require 的, 所以能从
node_modules
里面加载对应externals
的包。
开发时候的一些入口文件
main.ts
start:main
: 通过 ts-node 直接编译, 然后被electron
调用build:main
, 这是electron
调用的入口, 运行的环境就是node
, 会创建窗口,加载 renderer 脚本以及对应的 preload 脚本。最终输出到release/app/dist/main
目录中。
preload.ts
start:preload
: 开发环境下,把 preload 编译到.erb/dll
目录下build:main
: 生产环境下,同时编译main
和preload
文件
注入到窗口中的 preload
, 负责 IPC
通讯,开发环境下,会从 .erb/dll
下加载。生产环境,是和 main.ts
在同级。
mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728,
icon: getAssetPath('icon.png'),
webPreferences: {
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
});
renderer.ts
renderer 页面中加载的。
start:renderer
: 强制依赖dll
, 需要先构建dll
, 然后才能启动renderer
, html 页面中,会注入DLL
的脚本build:renderer
:所有依赖全部打包,所以无须dll
了
dll
这是为了开发环境的一种优化。把一些不需要经常变动的包,提前编译好,放在 .erb/dll
目录下,开发环境下,直接从这里加载,不需要每次都编译。
编译的实际,是在 postinstall
和 package
的时候, 或者手动触发 build:dll
, 输出内容到 .erb/dll
目录。
开发环境下,走 webpack.config.renderer.dev.dll.ts
, 提取 外层 package.json
中的 dependencies
, 生成 dll
。
生产环境下, 直接在 build:renderer
中完成构建, 不需要 dll
了。
开发阶段
yarn run start
会启动 yarn run start:renderer
, 它的 webpack.config.renderer.dev.ts
中, 有 setupMiddlewares
继续调用: start:preload
和 start:main
.
跨平台编译
如果项目没有特定平台的依赖需要编译的话, 是可以跨平台编译的, 比如在 Mac 上编译 Windows 的版本。
但是由于需要 code sign 等操作, 一般还是需要在对应平台上编译。
技术总结
要了解是否需要 native 编译的包, 不需要的话,构建就可以跨平台了。不过一般而言,还是会区分 Mac 和 Windows 的构建,因为需要 code sign 等操作。