窥探Electron React Boilerplate,熟悉搭建Electron开发环境

4,184 阅读5分钟

如果你对搭建Electron+React开发环境感兴趣,那么这一篇介绍Electron React Boilerplate不容错过。本文并不适合webpack零基础同学看,其中会省略webpack中常见的配置。(Electron React Boilerplate,以下简称erb)

1653585210(1).png

相关技术框架简介

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:preloadstart: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输入的路径,这里是源码

脚手架部分依赖包

  1. BundleAnalyzerPlugin 打包分析
  2. jest 测试
  3. detect-port 检查端口
  4. eslint 语法检查
  5. @pmmmwh/react-refresh-webpack-plugin 用于为 React 组件启用“快速刷新”(也称为热重载)
  6. concurrently 同步运行command
  7. electron-builder 打包electron应用
  8. husky git钩子