electron初探问题总结
使用electron时间不是很久,随着使用的深入慢慢的也遇到一些问题,下面总结一下遇到的问题与大家分享,避免趟坑。
主要问题汇总如下:
- webview与渲染进程renderer间通信
- BrowserWindow加载第三方网站,集成node模块时导致第三方模块不可用
- 预加载脚本preload的问题
- 渲染线程renderer中引入Electron报错
- 渲染进程使用require报Uncaught ReferenceError: require is not defined错
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文档还未形成之前。
4、渲染线程renderer中引入Electron报错
在使用webpack打包编译的renderer进程中,使用如下语句引入electron:
const { shell, BrowserWindow } = require('electron').remote;
打包完成后报fs.existsSync is not a function的错误,详细信息如下图所示:

即,electron/index.js文件中引入fs.existsSync语句造成的。
6 | function getElectronPath () {
7 | if (fs.existsSync(pathFile)) {
8 | var executablePath = fs.readFileSync(pathFile, 'utf-8')
主要原因还是因为webpack默认产出目标是web平台的js,其混淆了nodejs的标准模块系统,导致引入nodejs的模块时出现问题。对此github有对应的解决办法:
- Error while importing electron in react | import { ipcRenderer } from 'electron'
- Requiring electron outside of main.js causes a TypeError
即通过使用window.require代替require来引入electron,因为前者不会被webpack编译,在渲染进程require关键字就是表示node模块的系统;
其实,更佳的解决方案是通过webpack自身来帮我们解决,即修改webpack提供的target产出目标为electron,即:
- 修改electron主线程webpack的target配置项为
electron-main - 修改electron渲染线程的webpack的target配置项为
electron-renderer
这样就可以更好的解决上面的问题。
5、渲染进程使用require报Uncaught ReferenceError: require is not defined错
在将webpack打包输出目标为electron对应环境后,在主线程中使用BrowserWindow加载renderer线程页面:
var win = new BrowserWindow({
width: 600,
height: 800
})
win.loadURL(url)
因为渲染进程使用require引入node的模块,这时会报错Uncaught ReferenceError: require is not defined。原因应该是加载渲染进程的窗口没有集成node环境。
奇怪的是在electron3.x中并没有任何配置就集成了node环境,而升级到electron5.x就不行了,查询资料发现:
electron5.x的node集成环境默认是关闭的,这之前的版本是默认开启的。
所以,为了保持前后兼容,建议显示配置集成node环境,即nodeIntegration为true。
var win = new BrowserWindow({
width: 600,
height: 800,
webPreferences: {
nodeIntegration: true
}
})
参考文献
- jQuery isn't set globally because "module" is defined
- #217 Electron 深度实践总结
- Electron文档
- electron-webview完全指南
- electron 5.0.0 “Uncaught ReferenceError: require is not defined”
electron初探问题总结的更多相关文章
- Electron初探
H5开发桌面应用? 没错,H5现在也可以开发跨平台的桌面应用了,这意味着我们可以用网页来设计和制作桌面应用. 基于Node.js的Electron框架就可以实现桌面应用,比较有名的Electron框架 ...
- electron——初探
是什么? Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并到同一个运行时 ...
- Windows Electron初探
最近闲来无事,玩玩electron. 1.安装nodejs 下载地址:http://nodejs.cn/download/,下载64位.安装完成后,打开C:\Program Files\nodejs\ ...
- 初探Electron,从入门到实践
本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 在开始之前,我想您一定会有这样的困惑:标题里的Electron ...
- 初探Electron
Electron是什么? 官网是这么描述的:Build cross platform desktop apps with JavaScript, HTML, and CSS 翻译一下:使用JavaSc ...
- 2017-12-22 日语编程语言"抚子"-第三版实现初探
前文日语编程语言"抚子" - 第三版特色初探仅对语言的语法进行了初步了解. 之前的语言原型实现尝试(如编程语言试验之Antlr4+JavaScript实现"圈4" ...
- Electron使用与学习--(页面间的通信)
目录结构: index.js是主进程js. const electron = require('electron') const app = electron.app const BrowserWin ...
- Electron使用与学习--(基本使用与菜单操作)
对于electron是个新手,下面纯属个人理解.如有错误,欢迎指出. 一.安装 如果你本地按照github上的 # Install the `electron` command globally ...
- 初探领域驱动设计(2)Repository在DDD中的应用
概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的, ...
随机推荐
- easywechat微信开发SDK之小微商户进件(二)
正式开始进件之前需要准备几个东西 1.服务商商户号 2.API密钥 微信服务商后台中设置 3.APIv3密钥 微信服务商后台中设置 4.API证书路径 登录服务商后台下载 生成证书官方又文档的 很 ...
- 腾讯iphone面试题(转)
1Objective-C内部的实现 2CALayer和View的关系 3 http协议,tcp/ip 4 UITableView的那些元素是可以自定义的? 5 c语言的,定义变量,比如int,在什么情 ...
- 个人搭建后台管理模板 Bootstrap4 ,ASP.NET Core,EF Core,JWT
拥有一个美观好用的网站后台,是很多开发者的梦想,笔者在闲暇时间里搭建了一个不错的后台框架,这里分享诸位开发同仁. 项目地址:https://github.com/kongdf123/KentNoteB ...
- 【Python成长之路】python 基础篇 -- global/nonlocal关键字使用
1 课程起源 有一次在工作中编写python工具时,遇到一个 问题:从配置文件读取变量A后,无法在内存中把A的值改变成新的内容.为了解决"更新内存中变量"的这个问题,查找了一些帖子 ...
- 华为参与《基于5G技术的医院网络建设标准》的制定
[摘要] 5G 千兆网承载五地远程会诊,现场完成三例复杂性疑难重症远程病例讨论 [中国,北京,2019年9月4日] 金秋之际,在国家卫生健康委指导下,由中日友好医院•国家远程医疗与互联网医学中心•国家 ...
- deepin系统安装pip
Deepin系统安装pip Deepin系统通常自带了两个版本的python,一个python2,一个python3.可以在命令行输入这两个命令测试下是不是有两个版本,都是有两个版本都存在的情况下,安 ...
- JGit----将 Git 嵌入你的应用
如果你想在一个 Java 程序中使用 Git ,有一个功能齐全的 Git 库,那就是 JGit . JGit 是一个用 Java 写成的功能相对健全的 Git 的实现,它在 Java 社区中被广泛使用 ...
- 洛谷 P2342 叠积木 题解
本蒟蒻又来发题解了 这题是不是有点像并查集,但是那个询问的个数是不是有点骚: 所以,普通的并查集是无法解决这个问题的,这个时候就需要用到带权并查集了: 每次跑的时候都记录下它的下面有几个点,然后询问的 ...
- CF 526F Max Mex(倍增求LCA+线段树路径合并)
Max Mex 题目地址:https://codeforces.com/contest/1084/problem/F 然后合并时注意分情况讨论: 参考代码: #include<bits/stdc ...
- 【CuteJavaScript】Angular6入门项目(4.改造组件和添加HTTP服务)
本文目录 一.项目起步 二.编写路由组件 三.编写页面组件 1.编写单一组件 2.模拟数据 3.编写主从组件 四.编写服务 1.为什么需要服务 2.编写服务 五.引入RxJS 1.关于RxJS 2.引 ...