当你需要将一个vue
项目打包成electron
时,只需要正常的安装electron
依赖、electron-builder
依赖,正常的配置好主进程、预加载脚本、渲染进程即可。
依赖安装
这里默认你已经写好了一个vue
项目,脚手架为vite
,然后需要打包成electron
。
安装electron
pnpm add -D electron
安装electron
打包依赖
pnpm install electron-builder -D
为了使项目和electron
正常运行,需要先运行项目,使得其开发服务器的url
可以正常访问,然后再开启electron
去加载url
。 此处需要安装两个库:
pnpm install -D cross-env wait-on
cross-env
:该库让开发者只需要注重环境变量的设置,而无需担心平台设置wait-on
:等待资源,此处用来等待开发服务器的url
,然后开启electron
此处依赖准备完毕。
配置修改及运行
修改package.json
"scripts": {
"name": "snow-admin",
"private": true,
"version": "0.0.0",
"type": "commonjs",
"description": "snow-admin",
"main": "./electron/main.js",
"author": "wangfan",
"license": "MIT",
"dev": "vite",
"electron:dev": "wait-on tcp:5173 && cross-env VITE_USER_NODE_ENV=development electron .",
},
解释:
author、description为必填项
"main": "./electron/main.js"为主进程加载路径
"type": "commonjs"表示以commonjs运行
启动npm run electron:dev的时候,打开端口为5173,VITE_USER_NODE_ENV环境为development,启动electron .
在根目录新建electron
文件夹main.js
为主进程preload.js
为预加载脚本
修改main.js
中的内容
const { app, BrowserWindow } = require("electron");
const path = require("path");
// const NODE_ENV = process.env.VITE_USER_NODE_ENV;
// 创建一个窗口-封装
function createWindow() {
// 创建一个窗口
const win = new BrowserWindow({
width: 800, // 窗口宽度
height: 500, // 窗口高度
autoHideMenuBar: true, // 隐藏默认菜单
webPreferences: {
preload: path.resolve(__dirname, "./preload.js") // 加载预加载脚本,绝对路径
}
});
// 以url方式打开
win.loadURL("http://localhost:5173");
}
// 监听app的ready事件
app.on("ready", () => {
createWindow();
// window所有窗口关闭时,并且不是苹果系统,退出应用-管理窗口的生命周期
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
});
// 应用被激活时,窗口数量为0,自动创建一个窗口-管理窗口的生命周期
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
这里就是一个最基本的主进程逻辑,唯一不同的就是打开方式是以url
方式打开,路径为本地项目5173
端口
修改预加载脚本preload.js
中的内容
const { contextBridge } = require("electron");
const NODE_ENV = process.env.VITE_USER_NODE_ENV;
console.log("预加载脚本,运行环境", NODE_ENV, process);
contextBridge.exposeInMainWorld("myAPI", {
mytext: "这是暴露的变量"
});
这一步是为了让你知道electron
成功运行了,当你项目启动的时候,控制台会输出console.log
打印语句process
是只有node
端才能使用的字段,若浏览器成功输出,说明你成功调用nodeAPI
了
然后先启动你的vue项目
pnpm run dev
这里我的端口是5173
然后启动electron
项目
pnpm run electron:dev
在electron
中成功打开vue
项目,打开控制台可以看到预加载脚本console.log
成功输出了,说明vue
项目打包electron
成功了。
至于vue
项目如何与electron
主进程通信,这个就是electron
的基本知识了,这里不细讲。
通信的过程应该是这样的:vue项目(渲染进程) -> 预加载脚本(preload.js) -> 主进程(main.js)
在vue
项目中正常过的调用预加载脚本函数,然后预加载脚本发送事件到主进程,主进程监听事件做逻辑处理
例如:vue
项目中调用预加载脚本定义的myAPI.saveFile
函数,然后主进程监听事件
// vue项目
window.myAPI.saveFile(form.value.username);
// 预加载脚本preload.js
contextBridge.exposeInMainWorld("myAPI", {
mytext: "这是暴露的变量",
saveFile: data => {
console.log("调用预加载脚本");
ipcRenderer.send("file-save", data);
},
});
// 主进程main.js
ipcMain.on("file-save", ()=> {});
项目打包
在package.json
中修改
"scripts": {
"dev": "vite",
"electron:build": "cross-env VITE_USER_NODE_ENV=production electron-builder",
},
这里实际上是指定你的运行环境为production
,然后执行electron-builder
命令来打包electron
在package.json
中与scripts
同级,electron-builde
打包配置:
"build": {
"appId": "snow-admin",
"productName": "electron-snow",
"copyright": "Copyright © 2024",
"mac": {
"category": "public.app-category.utilities",
"icon": "./logo.ico"
},
"win": {
"icon": "./logo.ico",
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
]
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "sd-cashier"
},
"files": [
"dist/**/*",
"electron/**/*"
],
"directories": {
"buildResources": "assets",
"output": "dist_electron"
}
},
配置注释
"build": {
"appId": "your.id", // 应用的唯一ID
"productName": "YourProductName", // 安装后生成的文件夹和快捷方式的名称
"win": {
"icon": "./logo.ico", // 应用图标
"target": [
{
"target": "nsis", // 指定使用 NSIS 作为安装程序格式
"arch": ["x64"] // 生成64位安装包
}
]
},
"nsis": {
"oneClick": false, // 是否一键安装,如果为 false,则显示安装向导
"allowElevation": true, // 是否允许请求提升(以管理员身份运行)
"allowToChangeInstallationDirectory": true, // 是否允许用户更改安装目录
"createDesktopShortcut": true, // 是否在桌面上创建快捷方式
"createStartMenuShortcut": true, // 是否在开始菜单中创建快捷方式
"shortcutName": "YourAppName", // 快捷方式的名称
"uninstallDisplayName": "Your App", // 卸载时显示的名称
"license": "path/to/license.txt", // 许可证文件的路径
"installerIcon": "path/to/installer-icon.ico", // 安装程序图标的路径
"uninstallerIcon": "path/to/uninstaller-icon.ico", // 卸载程序图标的路径
"installerHeaderIcon": "path/to/header-icon.ico", // 安装向导头部的图标路径
"installerSidebarIcon": "path/to/sidebar-icon.bmp", // 安装向导侧边栏的图标路径(必须是 BMP 格式)
"runAfterFinish": true, // 安装完成后是否运行应用
"perMachine": true, // 是否为所有用户安装(而非仅当前用户)
"script": "path/to/custom-nsis-script.nsh", // 自定义 NSIS 脚本的路径
"compression": "lzma", // 压缩方式,可选值包括 'none', 'zip', 'lzma' 等
"artifactName": "${productName}-${version}-Setup.${ext}", // 自定义输出文件的名称
},
}
打包线上web项目
跟启动本地项目没有什么区别,由于我们将已有的web
端项目打包,所以很难做到将vue
项目完全迁移到electron
中,最简单的方法就是修改主进程中的win.loadURL("你的线上url")
;
具体是通过process.env.VITE_USER_NODE_ENV
来区分你的运行环境,这里做一个主进程的示例:
const NODE_ENV = process.env.VITE_USER_NODE_ENV;
// 创建一个窗口-封装
function createWindow() {
// 创建一个窗口
const win = new BrowserWindow({
width: 800, // 窗口宽度
height: 500, // 窗口高度
autoHideMenuBar: true, // 隐藏默认菜单
webPreferences: {
preload: path.resolve(__dirname, "./preload.js") // 加载预加载脚本,绝对路径
}
});
ipcMain.on("file-save", writeFile);
if (NODE_ENV == "development") {
win.loadURL("http://localhost:5173"); // 本地
} else {
win.loadURL("http://101.126.93.137:82"); // 线上
}
}
// 监听app的ready事件
app.on("ready", () => {
createWindow();
// window所有窗口关闭时,并且不是苹果系统,退出应用-管理窗口的生命周期
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
});
通过环境区分来判断你打开的项目
线上和本地其实是一样的,只要项目在electron
中正常打开就都具备与主进程通信的能力。
其实你的vue
项目是一个渲染进程,也就是web
端运行的,而electron
正好可以通过预加载脚本来让渲染进程和主进程通信,也就是说只要你的项目正常打开,它就运行在渲染进程,它就具备与主进程通信的能力。
打包生产环境dist到electron本地启动
需要先掌握上一节,《打包线上web项目》的基础知识,篇章为上一篇的进阶
由于electron
使用win.loadURL
来加载页面会有CSP(内容安全策略风险)
,并且它引用的是线上链接,所以非常不安全。
我们可以将vite+vue
生产环境的包打到electron
来生成应用,这样更安全,且不需要发布线上版本,安装即用。
首先你要先配置好你的启动环境,在我们本地开发的时候,electron
监听的是本地url
链接,若打包生产,则使用的是生产包资源(dist
)
配置启动环境
配置启动环境,本地项目运行,一键启动web端和electron端
先配置本地启动,通过concurrently
来同时启动多个命令,通过cross-env
来设置运行环境
pnpm add -D concurrently
pnpm install cross-env --save-dev
"scripts": {
"dev": "vite",
"start": "concurrently \"pnpm run dev\" \"pnpm run electron:dev\"",
"electron:dev": "cross-env VITE_USER_NODE_ENV=development electron .",
"electron:build": "vite build --mode production && cross-env VITE_USER_NODE_ENV=production electron-builder",
"build:dev": "vue-tsc && vite build --mode development",
"build:prod": "vue-tsc && vite build --mode production"
},
本地开发的时候使用pnpm run start
来同时启动pnpm run dev
、pnpm run electron:dev
两条命令pnpm run dev
就是正常启动本地vite
项目pnpm run electron:dev
就是启动electron
项目,在启动这条命令的时候,会通过cross-env
来设置环境变量VITE_USER_NODE_ENV=development
,主进程就可以通过VITE_USER_NODE_ENV
来判断当前运行的是哪个环境
在本地项目中,我们需要在vite.config.ts
中设置启动端口
server: {
port: 8080, // 设置端口号
cors: true, // 允许跨域
hmr: true, // 开启热更新
},
主进程中就可以根据当前环境来判断加载方式,若是开发环境就监听本地的8080
端口,若是生产环境则使用vite
打包后的dise/index.html
文件,这个是启动入口
这样做,你在本地开发的时候只需要运行pnpm run start
命令,就会启动本地项目以及electron
,由于配置了hmr
热更新,修改页面electron
项目也会同步更新。
打包生产环境,electron嵌入生产环境生成应用
我们在主进程中做了判断
if (process.env.VITE_USER_NODE_ENV == "development") {
win.loadURL("http://localhost:8080");
} else {
win.loadFile(path.resolve(__dirname, "../dist/index.html"));
}
若不是开发环境,则走生产环境,这里electron
加载的文件为vite
打包后的dist/index.html
文件,使用的本地资源进行打包。
在package.json
中我们配置了这么一条命令:
"scripts": {
"electron:build": "vite build --mode production && cross-env VITE_USER_NODE_ENV=production electron-builder",
},
首先需要搞清楚一件事,有些script
启动命令使用单个&
,有些使用两个&
● &
:同时启动多个命令
● &&
:依次启动多个命令
这里先启动vite build --mode production
打包生产环境,然后启动cross-env VITE_USER_NODE_ENV=production electron-builder
设置生产环境,并且使用electron-builder
打包应用。
我们稍后再运行打包命令,先配置打包路径
在主进程文件中配置预加载脚本的路径
打包配置,这里使用electron-builder
进行打包,在package.json
中配置,与scripts
同级
"build": {
"appId": "snow-admin",
"productName": "snow-admin",
"copyright": "Copyright © 2024",
"mac": {
"category": "public.app-category.utilities",
"icon": "./logo.ico"
},
"win": {
"icon": "./logo.ico",
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
]
},
"nsis": {
"oneClick": false,
"perMachine": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "sd-cashier"
},
"files": [
"dist/**/*",
"electron/**/*"
],
"directories": {
"buildResources": "assets",
"output": "dist_electron"
}
},
运行打包指令pnpm run develectron:build
生成应用程序
打包后的几种常见报错
1、安装应用后项目白屏
这种可能是vite
打包资源没有指定到正确路径,检查vite.config.ts
文件中的base
字段,将其改为'./'
。
在vite
官方文档上有说明:vite-base
注意:这个适用于嵌入形式开发,如果你修改了路径打包成electron后,再打包web端需要改回来
2、项目正常启动,但是预加载脚本运行报错
可能是预加载脚本资源路径报错导致,检查你的文件位置,若主进程和预加载脚本处于同级目录,这里就不能用../preload.js
将其改为preload.js
或./preload.js
即可
const win = new BrowserWindow({
// 省略其它...
webPreferences: {
preload: path.resolve(__dirname, "preload.js") // 加载预加载脚本
}
});
在这种资源嵌入打包的场景下,很多时候资源加载报错都是因为路径引入的问题导致,出现这种问题一定要好好检查一下各文件的所处位置和引入路径。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。