如果你对搭建Electron+React开发环境感兴趣,那么这一篇介绍Electron React Boilerplate不容错过。本文并不适合webpack零基础同学看,其中会省略webpack中常见的配置。(Electron React Boilerplate,以下简称erb)
相关技术框架简介
Electron:使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序,Electron 继承了来自 Chromium 的多进程架构,这使得此框架在架构上非常相似于一个现代的网页浏览器,一个主进程加多个渲染器进程组成一个Electron应用。
搭建Electron开发环境需要解决的关键问题
1 开发环境最重要的热更新
热更新主进程,启动electron
一般情况下,我们通过npx electron .
启动electron项目,通过package.json中的main找到入口文件启动,而不是通过yarn add electron
后引入,再通过node main.js
启动,如何是这样的话,我们可以通过nodemon main.js
进行热更新了,但是并不是这样的,这里我们需要引入electronmon
了,它的作用跟nodemon差不多,都是监听文件变化并重启应用,这样一来主程序的热更新就解决了。
热更新渲染进程,启动React开发环境
这个应该算是比较多人熟悉的吧,利用webpack-dev-server即可,可以知道的是使用webpack打包编译并不需要把js代码转到低版本ES5之类的操作,因为electron原本就是基于最新的Chromium,对新特性支持度很高,不要进行转化,webpack配置中target值需要设置为target: ['web', 'electron-renderer']
,让webpack知道你打包后的用途,webpack会根据目标值做对应的处理。
热更新preload文件
使用过electron的人都知道preload吧,在最新版本中,preload文件搭建React渲染进程和main主进程的桥梁,通过contextBridge.exposeInMainWorld()
将electron或者node的api或者自定义的函数暴露到window上,使得React代码中可以使用额外的api,跟主进程进行通信。或者直接处理信息状态。所以preload
的热更新也很有必要,其实electronmon
也会监听主程序引入的文件,区分是main主进程文件和renderer进程文件变化,主进程文件变化直接重启整个应用,渲染进程就重新加载这个文件或者地址,终端会提示如下面代码
[2] [electronmon] main file change: src\main\home.ts
[2] [electronmon] restarting app due to file change
[2] [electronmon] renderer file change: src\main\preload.ts
但主程序不能引入ts文件,所以用ts编写preload代码时需要再开一个webpack开启watch模式,然后主程序引入编译后的preload文件,watch模式下preload.ts文件变化会实时更新主程序引入的preload.js,electronmon会开始工作。
2 command命令顺序
在electron应用开发环境中,一般来说,我们本地开启的localhost服务加载时间是要比electron程序开启时间长的,所以erb让开启localhost服务的命令先执行,再由webpack-dev-server提供的devServer.setupMiddlewares
去开启子进程启动electron程序。在package.json的scripts中定义了start
,start:main
,start:preload
,start:renderer
,localhost服务即是我们的渲染进程start:renderer
,
"start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer"
这里先使用ts-node去执行一个检查函数,这个函数回去判断当前默认端口是否被占用了,如果没有被占用就执行npm run start:renderer
,然后进入webpack配置文件中使用setupMiddlewares调用spawn开启子进程执行start:preload
和start:main
3 如何支持typescript
在electron官网介绍中我们可以得知其完全支持ts编写,并拥有官方声明文件,但是我们运行electron应用使用的是npx,依赖于node,node不能直接执行ts文件,你可能想到用tsc监听转换再运行,但是效率很差,而ts-node能直接运行ts文件,也更加成熟文档,这使得应用整个启动过程更优雅。使用也很简单,ts-node提供了node标志, -r ts-node/register,可以在不使用ts-node的cli情况下注册使用ts-node,在erb中是这样使用的,这样在开发环境中也能编写ts代码了,而preload,renderer的代码编写的ts则是由webpack中的ts-load处理的
electronmon -r ts-node/register/transpile-only ./src/main/main.ts
生产环境与开发环境的部分重要区别
1 定义全局环境变量
无疑cross-env
这个包能够轻松提供跨平台的对全局变量进行定义。生成模式下cross-env NODE_ENV=production
,开发模式下cross-env NODE_ENV=development
2 渲染进程在不同环境下需要分开处理
在electron中主进程负责整个应用的,渲染进程负责单一窗口,渲染进程要么通过文件加载渲染,要么通过加载URL渲染,在erb中,有这么一个函数它定义了在不同环境下渲染模式,开发环境下使用new URl()
,生产环境使用file://
读取已经打包好的本地文件。
export let resolveHtmlPath: (htmlFileName: string) => string;
if (process.env.NODE_ENV === 'development') {
const port = process.env.PORT || 1212;
resolveHtmlPath = (htmlFileName: string) => {
const url = new URL(`http://localhost:${port}`);
url.pathname = htmlFileName;
return url.href;
};
} else {
resolveHtmlPath = (htmlFileName: string) => {
return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
};
}
那么开发环境下我们就需要借助Webpack-dev-server开启本地服务了,
3 preload引用路径
运行build使用webpack打包main主进程的代码,这其中webpack定义了两个入口文件一个main,一个preload,因为两者代码类型差不多,没有renderer的css或者html和静态资源,所以可以选择放在一个webpack打包构建,并且需要在main引用preload的地方进行判断是否已经打包完成的,通过app.isPackaged
判断是否应用已经打包,来选择路径,这里可以查看源码
webPreferences: {
preload: app.isPackaged
? path.join(__dirname, 'preload.js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
.erb/dll/preload.js
路径下就是dev开发环境下preload经webpack输入的路径,这里是源码
脚手架部分依赖包
- BundleAnalyzerPlugin 打包分析
- jest 测试
- detect-port 检查端口
- eslint 语法检查
- @pmmmwh/react-refresh-webpack-plugin 用于为 React 组件启用“快速刷新”(也称为热重载)
- concurrently 同步运行command
- electron-builder 打包electron应用
- husky git钩子