【Electron+Vue】【四】提前踩坑
本文介绍了桌面应用程序开发中存在的一些问题,加深了对 electron 的了解。
(一) 内存占用越来越大,运行越来越慢
背景
当应用放很久后,会越来越卡,打开任务管理器发现,electron 应用占用内存很大。
分析
这一大部分原因是 electron 在牺牲内存占用的基础上,将 electron.js 封装。所以,本身就比较耗内存,Windows 版一上来开 4 个线程,再加上业务代码用到一些类库。
解决方式
Electron 官网上也有介绍(https://www.electronjs.org/docs/tutorial/performance)。
谨慎地加载模块
过早的加载和执行代码
阻塞主进程
阻塞渲染进程
不必要的polyfills
不必要的或者阻塞的网络请求
打包你的代码
(二) electron程序显示了文件浏览器
背景
启动 electron-vue 项目的时候,会经常出现以下的情况:
为什么会显示文件浏览器呢?我的应用程序去哪了?
分析
出现上述这个错误,八成就是 src/renderer 包含错误。
如果 src/renderer 中出现错误,则会在首次运行时与 ESLint 产生冲突。接着,一个无效的 webpack 的 renderer.js 会被生成出来,它会打断 HtmlWebpackPlugin 创建 index.html。由于 webpack-dev-server 没有 index.html 可以提供服务,所以服务器失败,程序返回到文件浏览器。
解决方式
在终端下检查下爆红的错误,修复错误,然后用 CommandOrControl+R 刷新 electron 应用,就可以看到熟悉的应用页面。
(三) ReferenceError: process is not defined
背景
当你首次启动 electron-vue 项目时会遇到 process is not defined。
具体报错如下图:
ReferenceError: process is not defined
- index.ejs:11 eval
[.]/[html-webpack-plugin]/lib/loader.js!./src/index.ejs:11:2
- index.ejs:16 module.exports
[.]/[html-webpack-plugin]/lib/loader.js!./src/index.ejs:16:3
- index.js:284
[electron-demo]/[html-webpack-plugin]/index.js:284:18
- runMicrotasks
- task_queues.js:93 processTicksAndRejections
internal/process/task_queues.js:93:5
解决方式
网上说降低版本这种方式也可以。
我本地的 node 版本是 12.3.1,好像更新到 12 之前就一切正常。看样子,最新版本的 node 会出现了错误。
除此之外,我从这个 issue(https://github.com/SimulatedGREG/electron-vue/issues/871)中得到了解决方法:就是在 webpack.web.config.js 和 webpack.renderer.config.js 中的 HtmlWebpackPlugin 中加入如下代码即可:
// 模版需要的参数
// https://github.com/jantimon/html-webpack-plugin/blob/master/examples/template-parameters/webpack.config.js
templateParameters(compilation, assets, options) {
return {
// 编译
compilation: compilation,
webpack: compilation.getStats().toJson(),
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: options
},
process,
};
},
(四) electron 如何打开开发者工具devtools
背景
开发应用,如果没有开发者工具 devtools,那么开发效率会大大降低,用上开发者工具,无论在调试还是测试方面犹如蛟龙出海,游刃有余。
解决方式
利用 electron 的 webContents 对象打开及关闭 devtools。下面的例子中,我基于 main.js 中的 createWindow 中的 mainWindow.webContents 进行操作的。
打开 devtools:
mainWindow.webContents.openDevTools()
默认状态下,开发者工具的位置是上一次工具打开的位置(左边,右边,下边都有可能。取决于上一次的状态,但不会是分离状态,也没有处于顶部的状态)
应用右侧打开 devtools:
mainWindow.webContents.openDevTools({mode:'right'})
底部打开 devtools:
mainWindow.webContents.openDevTools({mode:'bottom'})
左侧打开 devtools:
mainWindow.webContents.openDevTools({mode:'left'})
分离状态打开 devtools:
mainWindow.webContents.openDevTools({mode:'detach'})
mainWindow.webContents.openDevTools({mode:'undocked'})
这两种情况下,devtools 都是不和主界面在一起的,都是分离状态。但是 undocked 状态下,这个开发者工具是可以合并到主界面中的。detach 状态下,是永久分离的。这个就是两者的区别。
关闭 devtools:
mainWindow.webContents.closeDevTools()
(五) 找不到electron依赖包
背景
我的应用明明安装了依赖包,却无法找到 electron 包时,报这个错误:
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
原因分析
经测试发现,electron 必须要安装在 devDependencies。
找到该代码在源码的位置,见 node_modules\electron\index.js:
var pathFile = path.join(__dirname, 'path.txt')
function getElectronPath () {
if (fs.existsSync(pathFile)) {
var executablePath = fs.readFileSync(pathFile, 'utf-8')
if (process.env.ELECTRON_OVERRIDE_DIST_PATH) {
return path.join(process.env.ELECTRON_OVERRIDE_DIST_PATH, executablePath)
}
return path.join(__dirname, 'dist', executablePath)
} else {
throw new Error('Electron failed to install correctly, please delete node_modules/electron and try installing again')
}
}
module.exports = getElectronPath()
如果是安装在 dependencies 下,就没有 path.txt。那么 node 就读取不到该文件,抛出 electron 安装失败的问题。
解决方式
重新安装:
npm install electron --save-dev
(六) electron-vue无法改变vuex状态
背景
Electron-vue 中添加 vuex 插件后,却无法使用。组件间根本无法改变 vuex 数据状态。
解决方案
首先,vuex-electron 的文档里写了:
In case if you enabled createSharedMutations() plugin you need to create an instance of store in the main process. To do it just add this line into your main process (for example src/main.js):import './path/to/your/store'
意思是如果启用了 createSharedMutations() 的插件,需要在主进程中创建一个 store 的实例,在主进程中(例如 src/main.js)添加 store 实例。
是否启用了 createSharedMutations 插件,见 src\renderer\store\index.js 文件:
const store = new Vuex.Store({
state,
getters,
actions,
mutations,
plugins: [
createPersistedState(),
createSharedMutations()
],
strict: process.env.NODE_ENV !== 'production'
})
开启多窗口共享后,在主进程加上这一句就行了,见 src\main\index.js 文件:
import '../renderer/store'
重启程序即可。
如果应用中,不需要多窗口共享状态,就不需要在主进程中添加 stote 实例,将 store 实例中 createSharedMutations 方法去掉。
(七) electron-vue中无法使用Element组件
背景
应用需要集成第三方 ui 组件,比如 element-ui,但是导入组件后却无法使用。
解决方案
查看这个 issue(https://github.com/SimulatedGREG/electron-vue/issues/361):
Okay, I am able to reproduce this issue now. It seems element-ui falls into that category of modules that need to be white-listed. If you go into .electron-vue/webpack.renderer.config.js, around line 21, you can add element-ui to the whiteListedModules list. After making that change, tooltips will work as expected.
大概的意思是似乎 element-ui 并不属于这一类的模块,需要那些列入“白名单”,如果你进入 electron-vue/webpack.renderer.config.js。
在大约 21 行左右找到 let whiteListedModules 将 element-ui 添加进去:
let whiteListedModules = ['vue', 'element-ui', 'vuetify']
let rendererConfig = {
devtool: '#cheap-module-eval-source-map',
entry: {
renderer: path.join(__dirname, '../src/renderer/main.js')
},
externals: [
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
],
一个关于此配置的重要的事情是,可以将特定的模块列入白名单,而不是把它视为 webpack 的 externals。并没有很多情况需要这个功能,但在某些情况下,对于提供原始的 *.vue 组件的 Vue UI 库,他们需要被列入白名单,以至于 vue-loader 能够编译它们。另一个使用情况是使用 webpack 的 alias,例如设置 vue 来导入完整的编译+运行环境的构建。因此,vue 已经在白名单中了。
(八) Electron无边框窗口中自定义窗口快捷键
背景
mainWindow = new BrowserWindow({
height: 720,
minHeight: 720,
minWidth: 1080,
width: 1080,
frame: false
})
设置了 frame 为 false 后,electron 就隐藏了工具栏,所有窗口都变成了无边框窗口。因此,窗口中缺少了必要的最小化、最大化、关闭的窗口快捷键。
解决方案
首先在 windowOperate.vue 页面中写入三个按钮,并将事件绑定:
// 从渲染器进程到主进程的异步通信。
// 使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主进程。
const {
ipcRenderer
} = require('electron')
onMinusSm () {
ipcRenderer.send('min')
},
onRectangle () {
ipcRenderer.send('max')
},
onCross () {
ipcRenderer.send('window-close')
}
上面三个方法的意思是:给主进程发送同步消息,触发特定的事件。onMinusSm 方法中 ipcRenderer 发送 min 事件,主进程就可以监听 min 事件。
在 src/main/index.js 中:
const {
// 从主进程到渲染进程的异步通信。
ipcMain
} = require('electron')
ipcMain.on('window-close', function () {
// close无法关闭程序
// mainWindow.close()
app.exit()
})
ipcMain.on('min', function () {
// 最小化窗口
mainWindow.minimize()
})
ipcMain.on('max', function () {
if (mainWindow.isMaximized()) {
// 将窗口从最小化状态恢复到以前的状态。
mainWindow.restore()
} else {
// 最大化窗口。
mainWindow.maximize()
}
})
主进程监听渲染进程的三个事件。如:主进程监听 min ,触发最小化窗口的方法。
注意:mainWindow.close() 不能关闭程序,需要使用 app.exit() 来关闭。
(九) 监听窗口状态,动态改变窗口最大化图标
背景
上一个问题解决了窗口最小化、最大化、关闭的窗口快捷键。但是,还缺少动态改变窗口最大化的快捷键。
解决方案
在 windowOperate.vue 中监听 main-window-max 事件,触发展示缩小图标; 在 windowOperate.vue 中监听 main-window-unmax 事件,触发展示最大化图标:
mounted () {
// 监听窗口状态,动态改变图片
this.changeWin()
},
changeWin () {
ipcRenderer.on('main-window-max', () => {
this.isRectangle = false
})
ipcRenderer.on('main-window-unmax', () => {
this.isRectangle = true
})
},
在 src/main/index.js 让主进程监听窗口 maximize 和 unmaximize 向子进程发送事件消息:
function createWindow () {}中插入
// 监听窗口状态,向渲染进程发送消息
// 窗口最大化时触发
mainWindow.on('maximize', function () {
mainWindow.webContents.send('main-window-max')
})
// 当窗口从最大化状态退出时触发
mainWindow.on('unmaximize', function () {
mainWindow.webContents.send('main-window-unmax')
})
(十) electron Uncaught TypeError: Cannot read property ‘app’ of undefined
背景
electron-vue 这个项目有一些缺陷,启动项目的时候会报错:
Uncaught TypeError: Cannot read property 'app' of undefined
at new ElectronStore (E:\eleftron-autoupdate-demo\node_modules\electron-store\index.js:8:55)
at a (E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:1365)
at a (E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:1102)
at E:\eleftron-autoupdate-demo\node_modules\vuex-electron\dist\persisted-state.js:1:3174
at E:\eleftron-autoupdate-demo\node_modules\vuex\dist\vuex.common.js:425:46
at Array.forEach (<anonymous>)
at new Store (E:\eleftron-autoupdate-demo\node_modules\vuex\dist\vuex.common.js:425:11)
at eval (webpack-internal:///./src/renderer/store/index.js:17:64)
at Module../src/renderer/store/index.js (http://localhost:9080/renderer.js:1583:1)
at __webpack_require__ (http://localhost:9080/renderer.js:791:30)
解决方案
给主窗口添加 enableRemoteModule 属性,使用 remote 模块:
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000,
webPreferences: {
nodeIntegration: true,
enableRemoteModule: true
}
})
总结
本文介绍了桌面应用程序开发中存在的一些问题,加深了对 electron 的了解。
————————————————
采纳自:https://blog.csdn.net/weixin_38465623/article/details/112442756
更多推荐
所有评论(0)