详解 Electron React Boilerplate
2022-03-17
Coding
Electron
ERB
React
👋 ‍️‍️阅读
❤️ 喜欢
💬 评论

详解 Electron React Boilerplate

Electron是基于Javascript构建桌面应用的框架。 而React是最流行的Javascript UI库。

为了能在Electron框架下更好地使用React,于是就有了 Electron React Boilerplate

本文基于ERB-4.5.0版本。

特性

ERB集成了丰富的特性,包括但不限于

  • webpack
    • asset import
    • dead code stripping
    • tree shaking
  • electron-rebuild
  • electron-builder
  • typescript
  • babel
  • lint
  • jest

这些内容都可以在官方文档中找到怎样使用,本文将不再赘述。

下面将详细讲解ERB的整体流程和各个组件如何协作,重在WHY,而不止于HOW。

scripts

使用ERB,主要有3个script会被直接用到,分别是start, build, package。 我们就每个script展开讲解。

start

start用于以开发模式启动

ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer

第一步,ERB会检查端口使用,如果被占用则会给出警告并退出。

接着,ERB会调用start:renderer

cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts

该命令调用了webpack启动dev server,配置文件位于./.erb/configs/webpack.config.renderer.dev.ts。 在这个config中主要配置了

在配置的最后onBeforeSetupMiddleware中,其又调用了npm run start:main以启动主进程。

cross-env NODE_ENV=development electron -r ts-node/register/transpile-only ./src/main/main.ts

主进程直接运行electron加载main.ts。在main.ts中创建了主窗口并加载了localhost:1212/index.html,即上面运行的dev server。

build

build脚本用于构建生产用的bundle。

concurrently "npm run build:main" "npm run build:renderer"

它并行地运行build:mainbuild:renderer两个脚本。

build:main

cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts

./.erb/configs/webpack.config.main.prod.ts文件中,主要配置了

build:renderer

cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts

./.erb/configs/webpack.config.renderer.prod.ts中主要配置了

  • start类似的
    • loader
    • HTMLWebpackPlugin
  • build:main类似的
    • TerserPlugin
    • BundleAnalyzerPlugin
  • 输出文件位于release/app/dist/renderer

package

package脚本用于打包最终的binary

ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never

它首先会掉npm run build来构建bundle,然后运行electron-builder,其会根据package.json中的配置进行打包。

  • app路径为release/app
  • 主入口为./dist/main/main.js,即build阶段构建的main bundle。
  • 代码文件会通过asar格式进行归档
  • windows会使用nsis打包最终安装包
  • 打包结果位于release/build (windows为exe安装程序)

结构

在了解了主要的scripts之后,我们应该对整个开发构建流程有了清晰的认识。 同时也会有一些新的问题,例如,还有一个没有讲解的postinstall脚本以及略显突兀的release/app文件夹。

双package.json

electron最终的binary会使用特定的electron-node而非标准版node,所以从npm获取到的原生native依赖无法正常运行。 为了能够在electron上使用这些native模块,我们需要对于electron重新构建。

这就需要用到electron-rebuild

electron-rebuild提倡使用双package.json结构以区分依赖和开发期依赖。

而ERB,由于需要使用webpack打包代码,又进一步对该结构进行了变种。

postinstall

package.json中,还定义了postinstall脚本,它会在每次npm install之后触发。

ts-node .erb/scripts/check-native-dep.js
&& electron-builder install-app-deps
&& cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts

首先我们调用了check-native-dep.js脚本以检查原生依赖,如果在package.json中定义了非dev的native依赖,则会报错退出。

接着,我们又调用了electron-builder install-app-deps。 这会自动进入release/app目录执行install

现在,我们进入到release/app/package.json,可以看到,它也有一个postinstall调用。

{
"electron-rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js",
"link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts",
"postinstall": "npm run electron-rebuild && npm run link-modules"
}
  • 首先调用electron-rebuild对原生模组进行了重新构建。
  • 然后调用link-modulesrelease/app/node_modules链接到src/node_modules,这样我们在src中的源代码也就能使用原生依赖了。

最后,在完成了install-app-deps之后,还调用了webpack构建dll以加快开发期速度。

添加依赖

综合上面两小节,我们了解了ERB的改进版双package.json结构。 在实践中,当我们需要添加依赖项时,只需要遵循一个原则。

非dev原生(或有原生依赖)依赖项,需要定义在release/app/package.json

例外

ERB的结构在开发和生产构建下都运行良好,但是仍有一些特殊情况无法处理。

当我们在测试中需要使用到原生模块时,会得到如下错误。

The module XXX was compiled against a different Node.js version using
NODE_MODULE_VERSION 99. This version of Node.js requires
NODE_MODULE_VERSION 93. Please try re-compiling or re-installing

原因是,native依赖已经被electron重新编译,无法适应你本地的node binary。 要解决这一问题,有一种方法和一种workaround,

一种方法是,使用electron来运行测试,详见此Stackoverflow。 这种做法的问题是,与IDE无法集成,测试结果只可以在命令行上看,而且当需要运行单个用例时也只能自己写command。

一种workaround是,当focus在单元测试而不需要运行electron时,阻止electron重新编译native依赖,这样就可以直接用node运行测试。 这一方法的缺点是需要手动切换环境。

结尾

至此,我们已经厘清了ERB中所有结构和流程。

在ERB中还有一些边角料(如lint,husky)和无用信息(如.github, .vscode以及package.json中的多余内容),你可以酌情自行删除。

在搞清楚了来龙去脉之后,你就可以轻松地开始编写Electron React应用了。


Copyright © 2020-2022 Dean Xu. All Rights reserved.