electron 12版本以后渲染进程引入electron会报错
原因(from 官网):
先上解决方案,容后解释。
方案一(官网不推荐):
首先在创建窗口的地方加上以下配置
mainWindow = new BrowserWindow({
show: true,
width: 1024,
height: 728,
webPreferences: {
// 预加载脚本
preload: path.join(__dirname, 'preload.js'),
// 关闭上下文隔离
contextIsolation: false,
nodeIntegration: true,
},
});
preload.js文件中这样写
const { ipcRendere } = require('electron');
contextBridge.exposeInMainWorld('myApi', {
// 这里注意避免将ipcRenderer等致命api直接挂载在window上,可能会导致安全问题
sendMsg: (msg) => ipcRenderer.send('ipc-example', msg)
})
接着在渲染进程的tsx文件中
window.myApi.sendMsg('message');
这样处理过后就可以使用window下挂载的方法进行消息发送和接收了
方案二(官网推荐):
首先创建窗口时候预加载文件perload文件的配置方法一致,但是要开启上下问隔离,即其他位置不动,只是开启上下文隔离 contextIsolation: true
payload.js文件中这样写
const { ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('myApi', {
sendMsg: (msg) => ipcRenderer.send('ipc-example', msg)
});
渲染进程的tsx文件中
window.myApi.sendMsg('message');
解释原理
问题一:预加载
预加载(preload)脚本包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码 。 这些脚本虽运行于渲染器的环境中,却因能访问 Node.js API 而拥有了更多的权限。
预加载脚本可以在 BrowserWindow 构造方法中的 webPreferences 选项里被附加到主进程。(from electron官网)
从上面官网的解答可以看出两点
- preload脚本在主进程main文件中引入,但是执行于渲染进程,也就是说可以获取到window对象。
- perload脚本先于网页内容开始加载,而且能够访问Node.js API。
基于官网的回答及总结的两点,我们大致可以明白预加载脚本的作用,即我们可以通过预加载脚本为window对象挂载一些node的api,例如封装后的ipcRenderer,注意避免将ipcRenerer这种致命api直接挂载在window上,会导致安全问题,可以将ipcRenderer封装后结合ts规定消息类型提高安全性。
问题二:上下文隔离是什么
上下文隔离功能将确保您的 预加载脚本 和 Electron的内部逻辑 运行在所加载的 webcontent网页 之外的另一个独立的上下文环境里。 这对安全性很重要,因为它有助于阻止网站访问 Electron 的内部组件 和 您的预加载脚本可访问的高等级权限的API 。
这意味着,实际上,您的预加载脚本访问的 window 对象并不是网站所能访问的对象。 例如,如果您在预加载脚本中设置 window.hello = 'wave' 并且启用了上下文隔离,当网站尝试访问window.hello对象时将返回 undefined。
自 Electron 12 以来,默认情况下已启用上下文隔离,并且它是 所有应用程序推荐的安全设置。
之前,在渲染进程中,预加载脚本暴露给已加载的页面 API 是一个常见的使用方式。 当上下文隔离时,您的预加载脚本可能会暴露一个常见的全局window对象给渲染进程。 此后,您可以从中添加任意的属性到预加载在脚本。
之后,Electron 提供一种专门的模块来无阻地帮助您完成这项工作。 contextBridge 模块可以用来安全地从独立运行、上下文隔离的预加载脚本中暴露 API 给正在运行的渲染进程。 API 还可以像以前一样,从 window.myAPI网站上访问。