前言🌱
通过之前对 Electron 的了解,现在多少也能看出 Electron 的一些特点。
其中,Main Process 用来调度各个 Renderer Process;而各个 Renderer Process 实际上就是 web+(比 web 功能要强,姑且就允许我这么叫一次吧),他们除了 web 应用本身所拥有的特征之外,还可以通过引入 Electron 来扩展,当然也可以使用 NodeJs 的特性,比如在 React 中使用 fs.writeFile()
(听起来很诡异)。
如果之前的意见记不清楚了的话,可以再去翻翻看《Electron:Web 应用桌面化》、《Electron:主进程与渲染器进程》。
本篇呢,主要是为了来总结一下如何将 React 与 Electron 结合起来,让编码更加高效。
为什么要引入 React ?
实际上在最初学习的时候直接在 Electron 的应用中写 html+js+css 感觉也不错,但是当场景稍微复杂起来后就会感觉写起来比较繁琐。
另外还有就是在切换页面的场景,如果复用渲染器进程而直接采用切换 Url 的方式虽然也可以完成导航,但是会有一个“白屏时间”让人挺不舒服的。如果每个页面都起一个自己的渲染器进程,由于新窗口的启动有一个过渡,因此不会感觉到“白屏时间”,但是总感觉每个页面都起一个渲染器进程也并不是适用于任意位置。
所以说 SPA 是非常合适的一个选择,至于选什么框架并不重要。
最基础的整合
通过分别在 Electrn 中添加 React 和在 React 中添加 Electron 作比较之后,我发现在 React 中添加 Electron 仿佛要简单一些(也可能目前场景比较简单🤔)。
新建一个 React App
yarn create react-app electron-react
结束之后跑起来这个站点,假设站点地址是 http://localhost:3000,成功执行就可以了,保持这个执行状态不用关闭。
添加 Electron
yarn add electron --dev
在 src/
目录下新建 main.js
入口文件,内容如下:
// src/main.js
const { app, BrowserWindow } = require('electron')
app.allowRendererProcessReuse = true
function createWindow () {
let win = new BrowserWindow({
height: 500,
width: 800,
webPreferences: {
nodeIntegration: true
}
})
win.loadURL(`http://localhost:3000`)
}
app.on('ready', () => createWindow())
之后修改 package.json
文件,改一下入口文件,加一个 script:
"main": "src/main.js",
"scripts": {
"start:main": "electron ."
}
执行
yarn start:main
不出意外应该是成功了的。
在 React 中使用 Electron
默认在 React 中 使用 require('electron')
是不行的,会报错:
报错的原因是通过 create-react-app 创建的应用中 target 是 web 环境 ,因此不能识别 node api。
下面通过两种途径可以来解决这个问题。
1. 绕过 Webpack 的检查机制解决
比较简单的处理办法就是使用 window.require('electron')
代替 require('electron')
。window 对象在 electron 中是指向 global 的,所以它在执行时可以找到 require 函数。
2. 修改 React Webpack 配置解决
为了验证上面报错原因的猜测,我尝试 eject 了一个项目去观察,配置中的 target 确实是缺失的,那么理论上把这个 target 修改为对应的 target 就可以支持 require('electron')
了。
显然我们需要的是:electron-renderer
。
为了修改这个 target,首先需要把 React 项目 eject:
npm run eject
Note: this is a one-way operation. Once you eject, you can’t go back!(此过程不可逆,请谨慎操作!)
弹出后,打开 config/webpack.config.js
文件,大约在 130 行左右,添加代码片段中标记的那一句,我截取了一小段代码:
return {
target: 'electron-renderer', // <- 添加这一句
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
好了,重新启动后 require('electron')
就生效了,值得注意的是 无法直接在 Chrome 中运行,必须从 Electron 中打开。
取消 React 默认打开浏览器的行为
你可能发现了,现在我们不在需要每次运行脚本后自动打开浏览器这个功能了,它反而成了一种麻烦事儿!为此,我搜集了一些资料,总结了关闭该默认行为的 2 中解决方案:
方法1
- bash:
bash 可能还是比较常用的一个 terminal
# 设置临时环境变量
BROWSER=none
# 执行
yarn start:render
#or
# 连续命令
BROWSER=none && yarn start:render
- cmd:
如果你用的是 cmd,你可以使用下面的方式
# 设置变量
set "BROWSER=none"
# 执行
yarn start:render
# or
# 连续命令
set "BROWSER=none" && yarn start:render
设置临时环境变量只需要一次就可以了,该变量只在当前打开的 cmd 中有效。
- pwsh:
powser shell 与 cmd 有所不同
# 设置变量
$env:BROWSER="none"
# 执行
yarn start:render
# or
# 连续命令(我这里尝试会卡住)
($env:BROWSER="none") -and (yarn start:render)
方法2
在根目录添加一个 .env
文件:
// .env
BROWSER=none
之后正常执行就可以。
打包🛠️
没有打包功能的 Electron App 就没有意义,毕竟软件做出来是给人用的🙃。
Electron 方面推荐有两个打包工具:
- electron-forge
- electron-builder
相对来讲,electron-forge 更加适合于从零开始,直接基于 electron-forge 提供的模板项目开始开发 electron 应用。而 electron-builder 适合于对已有项目的打包。
相信一般来到这里的大家或者我自己也是,已经准备好了一个项目,就差打包了,所以大家一般更倾向于使用 electron-builder。
安装 electron-builder
yarn add --dev electron-builder
配置 electron-builder
在根目录创建一个 electron-builder.yml
的配置文件,用于配置 electron-builder 打包相关内容。
appId: com.example.app
copyright: ©2020 bey6
productName: bey6
# asar 加密
asar: false
extends: null
# 目录
directories:
buildResources: assets/
output: dist/
files:
- package.json
- build/
- node_modules/
- src/main.js
dmg:
contents:
- type: link
path: /Applications
x: 410
y: 150
- type: file
x: 130
y: 150
win:
# 目标类型
target: nsis
nsis:
oneClick: false
# 允许修改安装路径
allowToChangeInstallationDirectory: true
# 安装给所有用户
perMachine: true
修改 package.json
- 修改 homepage
- scripts 中添加一个打包 win64 的脚本
"homepage": ".",
"scripts": {
"build:win64": "yarn build && electron-builder --win --x64"
},
修改 Main Process
// src/main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('path')
app.allowRendererProcessReuse = true
function createWindow () {
let win = new BrowserWindow({
height: 500,
width: 800,
webPreferences: {
nodeIntegration: true
}
})
// 修改这里
if (process.env.NODE_ENV === 'dev') win.loadURL(`http://localhost:3000`)
else win.loadFile(path.resolve(__dirname, '../build/index.html'))
}
// ...
打包
yarn build:win64
打包结束后会在根目录多出来一个 dist/
目录,执行其中的 .exe
即可完成安装。
小结
虽然没有写什么比较深入的东西,不过通过这一次从零到打包的学习过程,能够感觉到 Electron 技术栈本身还是需要一定的知识面的,否则做起来真的是困难重重。
文章花了较长的时间编写,可能会出现不对的地方,如果有,还请慷慨指出!
🌹🌹🌹
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。