文章主要记录了使用electron
日常开发中所遇到的一些坑以及怎样填坑,帮助其他开发的小伙伴少踩一些坑。建议关注收藏,以便遇到时候方便查阅! 如果觉得有用点个赞再走呗!
electron
这个框架我就不过多介绍了,是使用node
和Chromium
架构的一个桌面端框架,如果有了解使用web技术开发桌面端,这个框架多少会听说过或者正在使用。
下面就记录一下自己在阅读文档的一些疑问以及开发过程中踩过的坑!
electron?
-
Spectron
和Devtron
的作用?-
Spectron
可以和其他的mocha
等测试框架进行结合,测试electron
-
Devtron
是Electron DevTools的扩展,可以帮助你检查,监控和调试应用程序。默认是关闭状态
-
-
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
的作用?- 设置 HTTP 的 Content-Security-Policy 头部字段
- 为了防止XSS攻击,安全考虑可以在
content
中设置允许加载的脚本的源
-
electron-forge
的作用?- 是一个快速构建electron的构建工具,里面包含打包、自动更新等
- 内部书写
html
和js
为原生写法,未集成第三方框架
-
在
electron
中使用iframe
和webview
的的区别?- 官方建议使用
iframe
代替webview
,webview
标签可以加载一个访客模式的URL页面,由于这个标签是基于Chromium webview
,目前架构变化较快,不够稳定。但是webview
所提供的功能较多,比如控制访客能否前进后退等
- 官方建议使用
-
window.open()
使用native和chrome的区别是什么?- 在
electron
中使用window.open()
打开一个URL使用,会创建一个BrowserWindow
实例,使用的是native
的窗口,可以通过设置nativeWindowOpen: true
来使用chrome
内置的window.open()
,同步打开窗口
- 在
-
electron-packager
和electron-builder
的打包区别?为什么推荐使用electron-builder
?-
electron-packager
和electron-builder
都是用于electron应用打包的模块, 相比较electron-builder
有更丰富的功能,支持更多的平台,打包的文件更加轻量,支持非electron
内置的自动更新(内置的自动更新需上传到git等支持平台)
-
-
在
electron
中使用node
原生模块的时候,electron-rebuild
能够简化原生的重编译?- 由于
electron
内置的node
版本和你电脑本机的版本不一致,则在使用node
原生模块的时候可能会报错,Error: The module '/path/to/native/module.node'
- 有3中方式可以解决该问题(下面会详细介绍两种使用方法,其他方式参考官方文档)
- 由于
electron进程之间通讯
-
主进程向渲染进程通讯
- 主进程使用
win.webContents.send
发送消息 - 渲染进程使用
ipcRenderer.on
接收消息
- 主进程使用
-
渲染进程向主进程通信
- 渲染进程使用
ipcRenderer.send
或者ipcRenderer.invoke
发送消息 - 主进程使用
ipcMain.on
或者ipcMain.handle
接收消息
- 渲染进程使用
- 渲染进程向渲染进程通信
-
通知事件
- 通过主进程转发(Electron 5之前)
-
ipcRenderer.sendTo
(Electron 5之后)
-
数据共享
- web技术(localStorage、sessionStorage、indexedDB、可嵌入型数据库等)
- 使用remote(尽量少用,容易影响性能)
由于公司使用的技术栈是vue
,所以需要将electron
和vue
结合起来,当然结合的方式也不麻烦,这里我们选用了electron-vue
这个开源框架。它已经将两者结合起来,并且能够独立打包成web
,但在使用过程中还是有些疑问和坑的,记录一下
electron-vue 的坑与填坑?
-
这个框架使用
vue-electron
模块,它的作用是什么?- 将 electron API 附加到 Vue 对象,不需要显式的在vue中引入electron(
require('electron')
) -
vue-electron
源码很简单,将$electron
挂载到vue的原型上
const electron = require('electron') module.exports = { install: function (Vue) { Object.defineProperties(Vue.prototype, { $electron: { get () { return electron }, }, }) }, }
- 将 electron API 附加到 Vue 对象,不需要显式的在vue中引入electron(
-
这个框架使用
vuex-electron
模块,它的作用是什么?- 可以在多个进程中间可以共享状态,比如在
electron
的主进程和渲染进程中公用一个状态,并将数据存放在磁盘中
- 可以在多个进程中间可以共享状态,比如在
-
在主进程中使用
__dirname
与__filename
打包后,并不能得到我们预期的路径?- 在调用native的dll的时候也遇到这个问题了,打包之前能够获得正确路径,打包后文件会被放在app.asar这个虚拟文件中,路径就会错误
- 解决方法:
electron-vue
中提供了__static
全局变量解决了这个问题,只需要将静态文件放入到__static
文件夹即可(path.join(__static, '/xxx.dll')
) - 如果只使用
electron
本身这个框架,你需要自己设置开发时路径和打包后的访问路径
-
初始化完成项目后会报一个错误:
ReferenceError: process is not defined
- 可以在
index.ejs
中将<% if (!process.browser) { %>
修改成<% if (!require('process').browser) { %>
(如果需要打包成web,请不要使用该方法) - 或者在
webpack.renderer.config.js
修改以下代码(实际上是配置页面中使用的process
参数,如果需要打包成web,可以使用该方法,但不要在webpack.web.config.js
中添加该代码)
new HtmlWebpackPlugin({ filename: 'index.html', template: path.resolve(__dirname, '../src/index.ejs'), + templateParameters(compilation, assets, options) { + return { + compilation: compilation, + webpack: compilation.getStats().toJson(), + webpackConfig: compilation.options, + htmlWebpackPlugin: { + files: assets, + options: options + }, + process, + }; + }, minify: { collapseWhitespace: true, removeAttributeQuotes: true, removeComments: true }, nodeModules: process.env.NODE_ENV !== 'production' ? path.resolve(__dirname, '../node_modules') : false }),
- 可以在
-
构建完项目后
electron
版本默认是2.x, 升级版本后会报错module is not defined
- 原因新版本
electron
默认不开启node
集成,在main/index.js
创建窗口的时候加上以下代码
mainWindow = new BrowserWindow({ height: 563, useContentSize: true, width: 1000, + webPreferences: { + nodeIntegration: true + } })
- 原因新版本
-
报错
Unable to install vue-devtools
- 原因是
vue-devtools
需要外网下载,科学上网即可
- 原因是
-
在该项目中调用
vuex
的mutations
时,会报错Please, don't use direct commit's, use dispatch instead of this.
- 这里提示不能使用同步的方法修改,应该通过调用
actions
去触发mutations
- 原因是
vuex-electron
里面加载了多进程之间共享mutations
插件 - 解决方法:1.在
store/index.js
中将createSharedMutations
插件注释即可 - 2.通过调用
actions
去触发mutations
,并且在主进程main/index.js
加入该代码import '../renderer/store'
- 3.查询
vuex-electron
github,按照文档设置whitelist
,这里不赘述
- 这里提示不能使用同步的方法修改,应该通过调用
-
在
vuex
中存储的数据,即使刷新和重启项目,该数据依然存在(这里功能可以设置用户长期存储的数据)-
vuex-electron
是将数据存储在磁盘中,默认路径可以通过app.getPath('userData')
找到存储路径下面的一个vuex.json
的文件,安装不同的electron
应用,文件目录下面都会生成一个vuex.json
文件 -
vuex-electron
内部使用了electron-store
这个模块,这个模块可以set
数据,但是vuex-electron
并没有将暴露出来 - 解决办法: 如果你想和在web中一样,刷新或者关闭后,数据重置,直接在下面第9个问题这,将
plugins
加载的模块删除即可
-
-
使用npm run build:web
打包时候,报错Error: Can't resolve 'fs' in xxxx
- 修改
renderer/store/index.js
,在web中去除vuex-electron
并删除显示引入vuex-electron
import Vue from 'vue' import Vuex from 'vuex' - import { createPersistedState, createSharedMutations } from 'vuex-electron' import modules from './modules' Vue.use(Vuex) export default new Vuex.Store({ modules, + plugins: process.env.IS_WEB ? [] : [ + require('vuex-electron').createPersistedState(), + require('vuex-electron').createSharedMutations() ], strict: process.env.NODE_ENV !== 'production' })
- 修改
-
打包报错
- 这里最容易报错的就是
downloading parts=8 size=63 MB url=https://github.com/electron/electron/releases/download/vx.x/electron-vx.x-win32-x64.zip
失败 - 解决办法:手动去
https://npm.taobao.org/mirrors/electron
找到对应electron版本下载 - 将下载好文件手动放在
C:\Users\用户名\AppData\Local\electron\Cache
文件夹中即可(AppData是隐藏文件夹)
- 这里最容易报错的就是
electron调用native方法
安装环境(mac环境无需安装第1步)
- 管理员权限执行
npm install --global windows-build-tools
安装python和C++环境
如果无法安装可以单独安装
- python(v2.7 ,3.x不支持)
- visual C++ Build Tools,或者vs2015及以上
-
npm install -g node-gyp
编译原生node模块(electron使用node原生模块需要编译) -
node-gyp list
查看是否缺少node.lib 库,并按照提示安装node-gyp install
- 在
src/main/index.js
中启用渲染层node集成
通过 node-ffi 模块调用C/C++ dll
-
npm install ffi-napi --save
安装调用C/C++ dll的模块- 如果找不到python路径,设置python环境变量或者
npm config set python你的python路径
- 如果还不行尝试使用yarn安装
- 如果找不到python路径,设置python环境变量或者
-
npm install electron-rebuild ---save-dev
安装自动编译原生node模块- 如果不安装的话可以进行手动编译,方法如下
- 进入
node_module/ffi-napi文件夹
执行node-gyp rebuild --target='当前electron的版本' --arch=x64 --dist-url=https://atom.io/download/atom-shell
编译node原生模块 - arch : 计算机的架构(x64或者ia32),如果node环境是32位,那么这里就是ia32,如果是node环境是64位,那么这里就是x64。
- 如果路径错误,换成国内镜像路径 --dist-url=https://npm.taobao.org/mirror...
- 再进入
node_module/ref-napi文件夹
执行node-gyp rebuild --target='当前electron的版本' --arch=x64 --dist-url=https://atom.io/download/atom-shell
编译node原生模块
- 如果自动编译的话执行
npx electron-rebuild
,上步手动编译则不需要这一步了 -
剩下的就是在主进程里面调用
native
方法即可,渲染进程调用通过ipcRenderer
和ipcMain
通信调用即可,举个小例子// 主进程 // 调用示例 const ffi = require('ffi-napi') const CTEST = ffi.Library('dll文件路径', { // 文件内的方法和参数类型 'Add': ['float', ['float', 'float']], 'Hello': ['string', []], 'StrLength': ['int', ['string']] }) // 同步调用 CTEST.Hello() // 异步调用 CTEST.StrLength.async('1234', (error, res) => { console.log(error, res) })
这里有两点需要注意一下
-
如果没有使用
electron-vue
这个框架(electron-vue
已经处理好静态文件路径),需要注意打包后的静态文件路径会有些问题,可以在在package.json
文件中配置build后dll的文件存放"extraFiles": [ { "from": "", "to": "" } ]
- 64位的dll不能再32位机器上调用,会报错
通过 electron-edge-js 模块调用C# dll
-
npm install electron-edge-js --save
安装调用C# dll的模块 -
这里
electron
的版本不能为8.x,版本7.x的页面刷新有bug,目前这个模块支持情况* Electron 1.6.x - Node.js v7.4.0. * Electron 1.7.x - Node.js v7.9.0. * Electron 1.8.x - Node.js v8.2.1. * Electron 2.x - Node.js v8.9.3. * Electron 3.x - Node.js v10.2.0. * Electron 4.0.4+ - Node.js v10.11.0. * Electron 5.x - Node.js v12.0.0. * Electron 6.x - Node.js v12.4.0. * Electron 7.x - Node.js v12.8.1
// 主进程
// 调用示例
const edge = require('electron-edge-js')
const edgeDll = edge.func({
assemblyFile: 'dll文件路径',
typeName: "Edge_test.Class1",
methodName: "Concat"
})
edgeDll({ first: 'aaa', second: 'bb' }, function (error, result) {
if (error) throw error
console.log('C# DLL:',result)
})
## 通过robotjs控制鼠标键盘、node-serialport进行串口通讯等
1. 使用方法这里不再赘述,文档查询即可。这些模块也是node原生模块,因此需要编译
2. 自动编译同上`npx electron-build`,有时候自动编译不好使,就需要手动编译
3. 手动编译 `npm rebuild --runtime=electron --disturl=https://atom.io/download/atom-shell --target=<electron版本> --abi=<对应node版本的abi>`或者直接进入模块文件夹中通过node-gyp编译:`node-gyp rebuild`
4. abi查询网址:https://github.com/mapbox/node-pre-gyp/blob/master/lib/util/abi_crosswalk.json
## 自动更新
**由于项目代码是放在自己服务并且不会进行签名,所以放弃`electron`内置的自动更新。项目使用的打包方式是`electron-builder`,最终决定使用`electron-updater`模块进行自动更新,它不依赖任何服务器并且可以从S3, GitHub或者任何其它静态文件存储更新,避开了 Electron 内置的更新机制**
**mac上代码必须要进行签名**
这里给个简版示例
1. `npm install electron-updater --save` 安装自动更新模块
2. 主进程中写入更新代码
// 每次开启应用时候会去自动到文件服务器检查是否有更新,并自动更新重启
import { autoUpdater } from 'electron-updater'
autoUpdater.on('update-downloaded', () => {
autoUpdater.quitAndInstall()
})
app.on('ready', () => {
if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
})
```
-
配置打包更新服务器地址(这里配置从自己文件服务器获取更新)
"build": { "publish": { "provider": "generic", "url": "http://127.0.0.1:8080" // 服务器地址 } }
- 打包后安装,如果需要更新修改
package.json
的版本,重新打包,将.exe
latest.yml
.exe.blockmap
3个文件直接扔在文件服务器地址即可。下次用户打开应用便会自动更新
在electron中起个node服务
- 这里代码比较简单,提供个思路:在主进程中创建个子进程执行node服务(child_process.fork),子进程和主进程通过进程之间进行通信,在主进程拿到数据之后通过
ipcMain
和ipcRenderer
进行主进程和渲染层通信即可。
以上就是个人在阅读文档以及项目中遇到的部分问题和坑,记录分享一下,帮助其他小伙伴少走一些坑,感谢阅读!
如果文章让你有收获,欢迎关注公众号,不定时推送优质文章!!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。