vite+vue+electron打包成桌面应用


这些零碎的思想,是树叶沙沙之声;它们在我的心里,欢快地低语者。

接到的需求是将我们vue3项目打包成桌面应用,由于我们的项目是用vue-cli创建的,所以当时我用vue-cli-plugin-electron-builder去完成打包操作,中间踩了不少坑,会把遇到的问题记录下来,并分享给大家,但是我们今天核心的分享内容是基于vite的项目,所以vue-cli-plugin-electron-builder一笔带过。

vue-cli-plugin-electron-builder

1. 依赖包之间的版本冲突

我遇到的第一个问题就是版本问题,electron31.2.1要求最低的node版本是18,在项目里有这样一个包@achrinza/node-ipc9.2.3,我倒没有仔细去看是哪个包依赖的(我有点怀疑是vue-cli创建项目带进来的),总之node-ipc支持node的最高版本是17,尴尬了呀,搜索发现也有人遇到了这个问题,大家把node-ipc升级至9.2.5就能完美解决,ok搞定。(自己注意npm缓存哦)

@achrinza/node-ipc 是一个 Node.js 模块。它主要用于在 Node.js 环境中实现进程间通信(IPC)。

2. Error: error:0308010C:digital envelope routines::unsupported

主要是因为 nodeJs V17 版本发布了 OpenSSL3.0 对算法和秘钥大小增加了更为严格的限制,nodeJs v17 之前版本没影响,但 V17 和之后版本会出现这个错误。

在执行指令前加SET NODE_OPTIONS=–openssl-legacy-provider,如下

1
"build": "SET NODE_OPTIONS=--openssl-legacy-provider && electron:build",
1
2
Linux & Mac OS:export NODE_OPTIONS=--openssl-legacy-provider
Windows:set NODE_OPTIONS=--openssl-legacy-provider

3. 打包网络问题

electron打包的时候会在github上下载nsis等等包,所以需要我们改一下镜像。(自己注意npm缓存哦)

1
2
3
4
在控制台输入 npm config edit
弹出配置文件,把下面的镜像地址加入
electron_mirror=https://npmmirror.com/mirrors/electron/
electron-builder-binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/

4. 图标更换问题

在目录创建一个icons的文件夹,然后放入256256的ico格式,名为*icon**的文件即可,electron build的时候,会去更换。ico的格式,有在线转换工具的。

ok,接下来用自己家电脑,把vite vue从头打一遍

这里因为是vite vue所以,我选择用electron-build来打。

我们是用electron去打包,而不是基于electron去开发,所以electron相关的包只用于开发过程,所以要装到devDependencies里

1
2
安装相关依赖
yarn add electron electron-builder -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
在根目录创建main.js文件
const { app, BrowserWindow, } = require('electron')
const path = require('path')

// 创建一个浏览器窗口
function createWindow() {
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: true, // 允许在渲染进程中使用node api
contextIsolation: false, // 禁用上下文隔离,使得渲染进程和预加载脚本运行在同一个上下文中
enableRemoteModule: true, 启用了 remote 模块,使得渲染进程可以访问主进程的功能
},
})
mainWindow.loadFile(path.resolve(__dirname, './dist/index.html')) // 加载指定路径的HTML文件
}

app.whenReady().then(() => {
createWindow() // 当 Electron 初始化完成并且准备好创建浏览器窗口时,调用 createWindow 函数

app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
1
2
3
4
5
6
7
8
9
10
11
12
同样在根目录创建preload.js
// 它的主要作用是在渲染进程(即网页)加载之前,预先加载一些必要的代码和资源
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}

for (const dependency of ['chrome', 'node', 'electron']) {
replaceText(`${dependency}-version`, process.versions[dependency])
}
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
在创建一个打包配置文件electron-builder.json
{
"productName": "electron-build-test",
"files": ["./main.js", "./dist"],
"directories": {
"output": ".build"
},
"win": {
"target": [
{
"target": "nsis",
"arch": [
"x64",
"ia32"
]
}
],
"icon": "icons/icon.ico"
}
}

然后根目录创建一个icons文件,放一张icon.ico

1
2
3
package.json
然后我们需要删除type:module,这会导致打包的时候报错,具体原因我也没仔细研究,嘿嘿
"electron:build": "vite build & electron-builder build --config electron-builder.json"
1
2
vite.config.js
base: "./", // 应用的相对路径

执行yarn electron:build,搞定

我们在打包过程中可以看到这个

同样去package.json加上这些属性,而且应用的默认菜单也太丑了,我们去main.js加入mainWindow.setMenu(null)去隐藏默认菜单。

既然打包搞定了,那就再整个electron热更新吧,不然调试起来费劲,每次都要重新打包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
yarn add concurrently wait-on electron-reload -D
concurrently: 命令行工具,用于同时运行多个命令。它允许你在一个终端窗口中并行运行多个脚本。
wait-on: 命令行工具,用于等待某个资源(如文件、端口、HTTP 接口等)可用,然后再执行其它命令。
electron-reload: 用于自动重载的工具,当文件系统中的文件发生变化时,它会自动重载 Electron 应用。

package.json
"serve": "concurrently \"vite\" \"wait-on http://localhost:3000 && electron .\"", // 这里我们监听的端口是3000

vite.config.js
server: {
port: 3000,
hmr: true, // 热更新
},

然后我们再main.js的createWindow函数里新增监听
let isDebug = true;
// 配置热更新
if (isDebug) {
const elePath = path.join(__dirname, './node_modules/electron')
require('electron-reload')('./', {
electron: require(elePath),
})
// 热更新监听窗口
mainWindow.loadURL('http://localhost:3000')
// 打开开发工具
mainWindow.webContents.openDevTools()
} else {
// 生产环境中要加载文件,打包的版本
// Menu.setApplicationMenu(null)
// 加载 index.html
mainWindow.loadFile(path.resolve(__dirname, './dist/index.html')) // 新增
}

ok,到这里热更新也搞定了,就是打包的时候记得把isDebug修改为false

我的微信公众号: 梨的前端小屋


文章作者: 梨啊梨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 梨啊梨 !
  目录