记录一次在Electron Forge中render端使用ipcRenderer与mian进程通信的踩坑经历。
由于能查到的中文资料较少,但是Electron Forge官方文档说的也不是很清楚,如果你也遇到了和我同样的问题,希望对你有帮助。
目前(2021年8月29日),Electron有两种使用icpRenderer与主进程通信的方式:
- 在创建window的时候配置:nodeIntegration: true,然后在UI端就可以
import {ipcRenderer} from 'electron';
- 是使用官方推荐的contextIsolation。需要一个中介:preload.js。
于是我一个个尝试:
尝试nodeIntegration
第一步:按照Electron官网要求
const mainWindow = new BrowserWindow({
height: 600,
width: 800,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
});
第二步:在render进程引入ipcRenderer
import {ipcRenderer} from 'electron';
...
ipcRenderer.send("hi");
...
结果:不行。
尝试contextIsolation
第一步:创建preload.js,并利用contextBridge桥接全局变量(render端可以直接访问)
const { contextBridge, ipcRenderer } = require('electron');
// import { contextBridge, ipcRenderer } from 'electron';
contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {
hi() {
ipcRenderer.send('hi');
},
},
});
第二步:main中创建window时导入preload.js
const mainWindow = new BrowserWindow({
height: 600,
width: 800,
webPreferences: {
preload: path.join(__dirname,"preload.js")
},
});
第三部:在render端使用
window.electron.ipcRenderer.hi();
结果:失败。
1.由于使用了typescript,说我window上没有electron属性,所以改为:
const electron = (window as any).electron ? (window as any).electron : {send:()=>{}};
2.骗过typescript了,但是没啥反应,查看devtools说electron是undefined。怀疑引入preload.js没成功。所以开始各种改路径。
中间各种折腾这里不再赘述,最后通过官方文档加github中的几个issue把这两个问题都解决了,直接出结论:
第一种:直接在UI端import icpRenderer
如果你使用nodeIntegration:true的方式,即在UI端直接import ‘electron’的方式,请确保以下关键步骤正确:
- 创建window时设置:
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},
2.同时在package.json中设置
...
"config": {
"forge": {
...
"plugins": [
[
"@electron-forge/plugin-webpack",
{
...
"entryPoints": [
{
"html": "./src/index.html",
"js": "./src/renderer.ts",
"name": "main_window",
}
],
"nodeIntegration": true // 重点:在这里也要设置true
...
...
第二种:使用Context Isolation的方式(preload)
官方推荐使用该方式,因为nodeIntegration存在一定安全风险。
关键步骤如下:
- 在主进程(ElectronForge目录中为index.ts)
declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY : string;
...
const mainWindow = new BrowserWindow({
height: 600,
width: 800,
webPreferences: {
preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
},
});
...
2.在package.json中设置entry points
["@electron-forge/plugin-webpack",
{
"mainConfig": "./webpack.main.config.js",
"renderer": {
"config": "./webpack.renderer.config.js",
"entryPoints": [
{
"html": "./src/index.html",
"js": "./src/renderer.ts",
"name": "main_window",
"preload": { //
"js" : "./src/preload.js" // 这里是重点(看准位置哦)
} //
}
],
}
}
]
如果你没看懂或者还是有问题,也可以私信我,我们一起研究。