一个已用Vue全家桶开发好的后台管理系统。应客户需求,需要限制电脑使用,但是不限制IP,用BS模式无法实现,故用Electron把该项目打包成CS模式的桌面应用。
Electron部分,使用electron-builder打包程序,使用electron-updater自动更新程序。使用Vue CLI Plugin Electron Builder和Vue Cli3集成。
Vue CLI Plugin Electron Builder支持Electron中Vue的热加载,支持Electron部分的热加载,在vue.config.js中配置相关数据。
使用vue add electron-builder
在vue cli3中安装electron-builder, 然后配置打包相关的东西,就可以使用yarn electron:serve
开发,使用yarn electron:build
打包。最好使用yarn安装相关依赖
如果安装electron是卡死,请使用淘宝镜像安装。cnpm install electron -g
// 更多配置 https://www.electron.build/configuration/configuration
electronBuilder: {
builderOptions: {
appId: 'com.xxxxxx.example',
productName: 'XXXXX',
copyright: 'Copyright © 2018 XXXXXX',
artifactName: 'XXXX Setup ${version}.${ext}', // 安装包名
win: {
icon: 'public/logo.png',
target: {
target: 'nsis', // 打包为nsis安装文件,
arch: [
'x64',
'ia32'
] // 支持32、64位的Windows系统
}
},
nsis: {
oneClick: false, // 是否一键安装
allowToChangeInstallationDirectory: true // 允许用户选择安装位置
}
}
}
这里会自动同步package.json中的name、version、author、description,如果上面配置中没有对这些进行配置,那么会获取package.json中的数据
yarn add electron-updater
"electron:publish": "vue-cli-service electron:build --publish always"
更多配置。这里主要是为了执行yarn electron:publish
命令时,把最新的版本发布到GitHub的Release中 publish: {
provider: 'github',
repo: 'xxxx', // git仓库
owner: 'xxxx', // 拥有者
token: 'xxxxxxxxxxxxxxx', // gitToken
releaseType: 'release',
publishAutoUpdate: true // 发布自动更新(需要配置GH_TOKEN)。 默认true
}
const {autoUpdater} = require("electron-updater")
autoUpdater.autoDownload = false // 关闭自动更新
autoUpdater.autoInstallOnAppQuit = true // APP退出的时候自动安装
// 发送消息给渲染线程
function sendStatusToWindow(status, params) {
win.webContents.send(status, params)
}
autoUpdater.on('checking-for-update', () => {
sendStatusToWindow('Checking for update...')
})
autoUpdater.on('update-available', (info) => {
// 可以更新版本
sendStatusToWindow('autoUpdater-canUpdate', info)
})
// autoUpdater.on('update-not-available', (info) => {
// // 不能够更新
// })
autoUpdater.on('error', (err) => {
// 更新错误
sendStatusToWindow('autoUpdater-error', err)
})
// 发起更新程序
ipcMain.on('autoUpdater-toDownload', () => {
autoUpdater.downloadUpdate()
})
autoUpdater.on('download-progress', (progressObj) => {
// 正在下载的下载进度
sendStatusToWindow('autoUpdater-progress', progressObj)
})
autoUpdater.on('update-downloaded', (info) => {
// 下载完成
sendStatusToWindow('autoUpdater-downloaded')
})
// 退出程序
ipcMain.on('exit-app', () => {
autoUpdater.quitAndInstall()
})
app.on('ready', async () => {
if (isDevelopment && !process.env.IS_TEST) {
// Install Vue Devtools
await installVueDevtools()
}
createWindow()
// 每次运行APP检测更新。这里设置延时是为了避免还未开始渲染,更新检测就已经完成(网速超快,页面加载跟不上)。
setTimeout(() => {
// 检测是否有更新
autoUpdater.checkForUpdates()
}, 1500)
})
<el-dialog
title="应用更新......"
:visible="showUpdater"
:close-on-click-modal="false"
:close-on-press-escape="false"
:show-close="false"
width="620px"
top="26vh"
center>
<template v-if="downloadProcess">
<p>{{'当前:' + downloadProcess.transferred + ' / 共' + downloadProcess.total}}</p>
<el-progress :text-inside="true" :stroke-width="18" :percentage="downloadProcess.percent"></el-progress>
<p>正在下载({{downloadProcess.speed}})......</p>
</template>
</el-dialog>
js部分
export default {
name: 'App',
data() {
return {
showUpdater: false,
downloadProcess: null
}
},
created() {
// 仅在Electron模式下(为了让非Electron后能够正常运行,添加的判断)
if (process.env.IS_ELECTRON) {
const { ipcRenderer } = require('electron')
// 发现新版本
ipcRenderer.once('autoUpdater-canUpdate', (event, info) => {
this.$confirm(`发现有新版本【v${info.version}】,是否更新?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
ipcRenderer.send('autoUpdater-toDownload')
})
})
// 下载进度
ipcRenderer.on('autoUpdater-progress', (event, process) => {
if (process.transferred >= 1024 * 1024) {
process.transferred = (process.transferred / 1024 / 1024).toFixed(2) + 'M'
} else {
process.transferred = (process.transferred / 1024).toFixed(2) + 'K'
}
if (process.total >= 1024 * 1024) {
process.total = (process.total / 1024 / 1024).toFixed(2) + 'M'
} else {
process.total = (process.total / 1024).toFixed(2) + 'K'
}
if (process.bytesPerSecond >= 1024 * 1024) {
process.speed = (process.bytesPerSecond / 1024 / 1024).toFixed(2) + 'M/s'
} else if (process.bytesPerSecond >= 1024) {
process.speed = (process.bytesPerSecond / 1024).toFixed(2) + 'K/s'
} else {
process.speed = process.bytesPerSecond + 'B/s'
}
process.percent = process.percent.toFixed(2)
this.downloadProcess = process
this.showUpdater = true
})
// 下载更新失败
ipcRenderer.once('autoUpdater-error', (event) => {
this.$message.error('更新失败!')
this.showUpdater = false
})
// 下载完成
ipcRenderer.once('autoUpdater-downloaded', () => {
this.$confirm(`更新完成,是否关闭应用程序安装新版本?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
ipcRenderer.send('exit-app')
})
})
}
},
发布到GitHub虽然实现自动推送等功能,但是在国内更新下载的速度太慢。所以推荐后端搭建文件存储服务器,或者使用七牛云等云存储服务器。这里以七牛云示例。
"electron:publish": "vue-cli-service electron:build --publish always"
脚本命令也就意义不大了。和使用yarn electron:build
是一样的效果 publish: {
provider: 'generic',
url: 'http://xxx.xxxx.com/app/' // 七牛云存储服务器的下载链接。下面必须要lasted.yml文件和需要更新的exe文件
}
然后后面的操作就和发布到GitHub一样的。需要注意的是,有的electron-builder版本不能正确获取到publish的配置,所以需要在electron的入口文件手动设置feedURL。
// 在开启更新监听事件之前设置
autoUpdater.setFeedURL({
provider: 'generic',
url: 'http://xxxx.xxxx.com/app/' // 一定要保证该地址下面包含lasted.yml文件和需要更新的exe文件
})
Error: C:\Users\Vincent\AppData\Local\electron-builder\Cache\nsis\nsis-3.0.3.2\Bin\makensis.exe exited with code 1
Error output:
!include: could not find: "E:\WorkFile\xxx\iwiteks_xxxx\node_modules\app-builder-lib\templates\nsis\include\StdUtils.nsh"
Error in script "<stdin>" on line 1 -- aborting creation process
Uncaught TypeError: fs.existsSync is not a function
解决方案: 渲染线程中的Electron相关代码添加process.env.IS_ELECTRON
判断。
https://github.com/lytian/electron-builder-demo