您的位置:首页 > 其它

electron初探问题总结

2019-06-10 14:41 671 查看

使用electron时间不是很久,随着使用的深入慢慢的也遇到一些问题,下面总结一下遇到的问题与大家分享,避免趟坑。

1、webview与渲染进程renderer间通信

与渲染进程之间的通信不同,渲染进程与webview之间的通信,在webview层通过调用

sendToHost
方法来向渲染进程通信;而在渲染进程测通过webview提供的
ipc-message
事件来向webview通信。具体如下面代码所示:

// renderer环境,获取webview,然后注册事件
webview.addEventListener('ipc-message', (event) => {
// 通过event.channel的值来判断webview发送的事件名
if (event.channel === 'webview_event_name') {
console.log(event.args[0]) // 123
}
})
webview.send('renderer_event_name', '456')

// webview环境
const {ipcRenderer} = require('electron')
ipcRenderer.on('renderer_event_name', (e, message) => {
console.log(message); // 456
ipcRenderer.sendToHost('webview_event_name', '123')
})

2、BrowserWindow加载第三方网站,集成node模块时导致第三方模块不可用

具体来说,就是在使用

new BrowserWindow
时,配置其webPreferences选项的
nodeIntegration
值为true,即:

new BrowserWindow({
webPreferences: {
nodeIntegration: true  // 注入node模块
}
})

这样,第三方网站按照CMD格式加载前端模块时如下所示,

!function(a, b) {
"object" == typeof module && "object" == typeof module.exports ? module.exports = a.document ? b(a, !0) : function(a) {
if (!a.document)
throw new Error("jQuery requires a window with a document");
return b(a)
}
: b(a)
}(this, fn);

可以看出,若electron窗口配置集成node模块的话,前端模块占用了node关键字

module
,导致前端页面的模块成了node的模块,以jQuery为例,依赖jQuery的模块会出现如下错误信息:

Uncaught ReferenceError: $ is not defined

知道问题所在,解决问题有两种思路:

  • 不启用node功能,即设置

    nodeIntegration: false
    。这种方式比较粗暴,不能更好的拓展electron应用

  • 在页面加载模块依赖之前改变

    module
    ,之后恢复module指向node模块

针对第二种方法,github上有人提出解决方案。我们在不可控的加载第三方网站时,利用BrowserWindow的前置注入脚本

preload
来提供修改module指向,可参考代码如下:

// renderer
var win = new BrowserWindow({
...
webPreferences: {
nodeIntegration: true,
preload: process.cwd() + '/app/resource/preload.js'
}
});

// preload.js

// electron的BrowserWindow设置nodeIntegration为true时,导致页面可以访问node的module影响页面正常模块引入功能,如jQuery
document.addEventListener('DOMNodeInserted', function(event){
// 页面内容加载之前需要引入的一些代码
if (document.head && !document.getElementById('module')) {
var script = document.createElement('script');
script.setAttribute('id', 'module');
script.innerHTML = "if (typeof module === 'object') {window.module = module; module = undefined;}"
document.head.appendChild(script);
}

});
document.addEventListener('DOMContentLoaded', function(event) {
// 页面内容加载之后需要引入的一些操作
var script = document.createElement('script');
script.innerHTML = `if (window.module) module = window.module;`
document.body.appendChild(script);
})

3、预加载脚本preload的问题

BrowserWindow
提供的
preload
的配置是为了在页面第一次加载文档之前预先加载js脚本文件,其需要注意3个问题:

  • preload配置值不能直接为脚本字符串,否则不会执行
  • preload配置的脚本文件路径,只能为本地文件,其协议必须是file:asar:二者之一
  • preload脚本仍然有能力去访问所有的 Node APIs, 即使配置nodeIntegration: false。但是当这个脚本执行执行完成之后,通过Node 注入的全局对象(global objects)将会被删除。

preload是在脚本加载之前执行,其有三个阶段如下,具体可以参考#217 Electron 深度实践总结

// ---------------------------------------------------
// 第一阶段:在页面加载之前需要执行的相关代码
// ...

// -------------------------------------------------------
document.addEventListener('DOMNodeInserted', (event) => {
// 第二阶段:页面内容加载之前需要引入的一些代码
// ...
})

// -------------------------------------------------------
document.addEventListener('DOMContentLoaded', (event) => {
// 第三阶段:页面内容加载之后需要引入的一些操作
// ...
})
// -------------------------------------------------------

可以看出:

preload环境
可以使用Node API,又能访问DOM、BOM的特殊环境,即使dom文档还未形成之前。

参考文献

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: