第一次开发桌面应用。在此记录使用electron-vue搭建桌面版应用所遇到的问题。
process is not defined
按照官网步骤搭建项目,运行npm run dev 时出现 process is not defined 错误。
解决方案:
在.electron-vue/webpack.renderer.config.js和.electron-vue/webpack.web.config.js文件中找到HtmlWebpackPlugin代码段并更改为如下代码:
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
}),
打包找不到文件报错
第一次运npm run build时报了一大堆文件下载错误,比如electron-vxxx-winxxx.zip 、nsis-xxx等
解决方案:
自己去taobao镜像网站或github上下载相关版本的文件包,放入本地相关目录下。
自定义桌面窗口栏目
通过配置主进程src\main\index.js文件相关属性,完成窗口自定义
import { app, BrowserWindow, ipcMain} from 'electron'
mainWindow = new BrowserWindow({
height: 880,
useContentSize: true,
width: 1200,
minWidth: xxx,
minHeight: xxx,
title: "XXX",
frame: false, //添加后自定义标题//自定义边框
resizable: false, //可否缩放
movable: true, //可否移动
})
// 相关事件
ipcMain.on('close', e => {
mainWindow.close()
})
ipcMain.on('minimize', e => {
mainWindow.minimize()
})
ipcMain.on('unmaximize', e => {
mainWindow.unmaximize()
})
ipcMain.on('maximize', e => {
mainWindow.maximize()
})
vue页面监听事件
const { ipcRenderer } = require("electron");
methods:{
minimize() {
ipcRenderer.send("minimize");
},
// 文档说可以用这个方法mainWindow.isMaximized()判断窗口是否最大化,但是我测试没有效果,所以就自己定义了一个状态
maximize() {
if (this.isMaxSize) {
ipcRenderer.send("unmaximize");
} else {
ipcRenderer.send("maximize");
}
this.isMaxSize = !this.isMaxSize;
},
close() {
ipcRenderer.send("close");
}
}
打包相关配置
1、图标命名自定义
修改package.json文件,在build中配置自定义图标路径和安装名称,需要在build文件夹中放置自定义图标
"build": {
"win": {
"icon": "build/icons/icon.ico",
"artifactName": "${productName}_Setup_${version}.${ext}"
}
},
2、打包后应用安装目录自定义
修改package.json文件,在build中添加配置
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"perMachine": true
},
3、自动检测版本并更新
修改package.json文件,在build中添加配置
"publish": [{
"provider": "generic",
"url": "http://xxxxxxx/download/" // 打包生成的exe安装包和latest.yml存放路径,浏览器输入地址能下载这两个文件
}]
安装 electron-updater,在 src\main\index.js中添加更新事件
import {
autoUpdater
} from 'electron-updater'
// 和package.json中配置的下载地址一致
let feedUrl = "http://xxxxxxx/download/";
//检测版本更新
updateHandle(mainWindow, feedUrl);
function updateHandle(window, feedUrl) {
mainWindow = window;
let message = {
error: '检查更新出错',
checking: '正在检查更新……',
updateAva: '检测到新版本,正在下载……',
updateNotAva: '现在使用的就是最新版本,不用更新',
};
//设置更新包的地址
autoUpdater.setFeedURL(feedUrl);
//监听升级失败事件
autoUpdater.on('error', function (error) {
sendUpdateMessage({
cmd: 'error',
message: error
})
});
//监听开始检测更新事件
autoUpdater.on('checking-for-update', function (message) {
sendUpdateMessage({
cmd: 'checking-for-update',
message: message
})
});
//监听发现可用更新事件
autoUpdater.on('update-available', function (message) {
sendUpdateMessage({
cmd: 'update-available',
message: message
})
});
//监听没有可用更新事件
autoUpdater.on('update-not-available', function (message) {
sendUpdateMessage({
cmd: 'update-not-available',
message: message
})
});
// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
sendUpdateMessage({
cmd: 'download-progress',
message: progressObj
})
});
//监听下载完成事件
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl) {
sendUpdateMessage({
cmd: 'update-downloaded',
message: {
releaseNotes,
releaseName,
releaseDate,
updateUrl
}
})
//退出并安装更新包
autoUpdater.quitAndInstall();
});
//接收渲染进程消息,开始检查更新
ipcMain.on("checkForUpdate", (e, arg) => {
//执行自动更新检查
// sendUpdateMessage({cmd:'checkForUpdate',message:arg})
autoUpdater.checkForUpdates();
})
}
//给渲染进程发送消息
function sendUpdateMessage(text) {
mainWindow.webContents.send('message', text)
}
在App.vue中添加检测更新事件
<script>
const ipcRenderer = require("electron").ipcRenderer;
//接收主进程版本更新消息
ipcRenderer.on("message", (event, arg) => {
// for (var i = 0; i < arg.length; i++) {
if ("update-available" == arg.cmd) {
} else if ("download-progress" == arg.cmd) {
//更新升级进度
alert("更新中");
console.log(arg.message.percent);
} else if ("error" == arg.cmd) {
alert("更新失败");
}
}
});
//20秒后开始检测新版本
let timeOut = window.setTimeout(() => {
console.log("检查更新");
ipcRenderer.send("checkForUpdate");
}, 2000);
clearTimeout;
//间隔1小时检测一次
let interval = window.setInterval(() => {
ipcRenderer.send("checkForUpdate");
}, 3600000);
</srript>
首先将打包成功后生成的exe安装文件和latest.yml放到配置的下载服务器上,再修改package.json中的版本号,重新打包新的版本,把生成的安装文件和latest.yml放到下载服务器同一个位置,latest.yml会覆盖上一次生成的。应用会通过检测这个文件判断是否有新版本
"version": "0.0.2", // 打包版本号
注意:用vue-electron脚手架搭建的应用electron版本是2.xx的,我查资料说版本太低不支持自动检测更新,所以我最开始就把electron升级了,没有测试2版本是否可以自动检测更新;自动更新成功后发现每次更新都需要重新安装一次,很不友好。如果有人了解局部更新的知识,我想请教学习,谢谢。
打包安装引入外部exe或者dll文件
由于项目中需要启动另外的exe程序,所以必须把其他exe程序和electron关联起来安装
修改package.json文件,配置需要引入的相关exe程序。
"extraResources": {
"from": "./extraResources/",
"to": "./extraResources/"
}
在src\main\index.js中使用chile_process
const {
spawn
} = require('child_process')
const vmPath = require('path').join(process.cwd(),'/resources/extraResources/xxx.exe').replace(/\\/g, '\\\\')
ipcMain.on('connect-server', (e, appUrl) => {
//spawn("D:/xxx/xxx/=xxx.exe") 开发模式写绝对路径
spawn(vmPath) // 打包安装后的路径
})
路径方面的问题,借用https://segmentfault.com/a/1190000018878931 原作者的话
使用 nodeJS 的被执行 js 文件的绝对路径:__dirname。
返回: D:\【文件夹】\win-ia32-unpacked\resources\app.asar\dist\electron
使用 electron 文档中提到的:“当前应用程序所在目录”:app.getAppPath()。
返回: D:\【文件夹】\win-ia32-unpacked\resources\app.asar
使用 process.execPath 即可获取: D:\【文件夹】\build\win-ia32-unpacked\vsqx.exe
使用 process.cwd() 即可获取: D:\【文件夹】\build\win-ia32-unpacked
最终我选用process.cwd()方法,完成在安装程序中启动内部exe程序