RuoYi-Vue3跨平台开发探索:Electron桌面应用改造实践
引言:从Web到桌面的无缝迁移
你是否还在为企业级后台系统的跨平台部署而烦恼?是否希望将现有的Web应用快速转化为功能完备的桌面应用,同时保留原有的所有功能和用户体验?本文将带你深入探索如何将基于Vue3 & Vite、Element Plus构建的RuoYi-Vue3权限管理系统,通过Electron框架改造为跨平台桌面应用,解决Web版在特定场景下的局限性,提升企业内部系统的安全性和用户体验。
读完本文,你将获得:
- 一套完整的RuoYi-Vue3桌面化改造方案
- Electron与Vue3项目的整合技巧
- 桌面应用的打包与分发策略
- 常见问题的解决方案与性能优化建议
一、Electron改造前的技术栈分析
1.1 原项目技术栈概览
RuoYi-Vue3作为一款成熟的权限管理系统,其前端技术栈如下:
| 技术 | 版本 | 作用 |
|---|---|---|
| Vue | 3.5.16 | 核心前端框架 |
| Vite | 6.3.5 | 构建工具 |
| Element Plus | 2.10.7 | UI组件库 |
| Vue Router | 4.5.1 | 路由管理 |
| Pinia | 3.0.2 | 状态管理 |
| Axios | 1.9.0 | HTTP客户端 |
1.2 为什么选择Electron
Electron作为一个跨平台桌面应用开发框架,具有以下优势:
二、Electron整合实战
2.1 环境准备与依赖安装
首先,我们需要为RuoYi-Vue3项目添加Electron相关依赖:
# 安装Electron核心依赖
npm install electron electron-builder --save-dev
2.2 项目结构调整
为了支持Electron,我们需要在原有项目结构基础上添加以下文件:
RuoYi-Vue3/
├── electron/
│ ├── main.js # Electron主进程
│ └── preload.js # 预加载脚本
├── package.json # 添加Electron脚本和配置
└── vite.config.js # 调整Vite配置以支持Electron
2.3 主进程实现
创建electron/main.js文件,作为Electron应用的入口点:
const { app, BrowserWindow, ipcMain, Menu } = require('electron');
const path = require('path');
const url = require('url');
// 关闭默认菜单
Menu.setApplicationMenu(null);
let mainWindow;
function createWindow() {
// 创建浏览器窗口
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
title: 'RuoYi-Vue3管理系统',
icon: path.join(__dirname, '../src/assets/logo/logo.png'),
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
enableRemoteModule: false,
preload: path.join(__dirname, 'preload.js')
}
});
// 加载应用
const startUrl = process.env.NODE_ENV === 'development'
? 'http://localhost:8080'
: url.format({
pathname: path.join(__dirname, '../dist/index.html'),
protocol: 'file:',
slashes: true
});
mainWindow.loadURL(startUrl);
// 开发环境下打开开发者工具
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools();
}
// 窗口关闭事件
mainWindow.on('closed', () => {
mainWindow = null;
});
}
// 应用就绪后创建窗口
app.whenReady().then(createWindow);
// 所有窗口关闭时退出应用
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
// 激活应用时创建窗口(macOS)
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});
// 主进程与渲染进程通信示例
ipcMain.on('window-minimize', () => {
mainWindow.minimize();
});
ipcMain.on('window-maximize', () => {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize();
} else {
mainWindow.maximize();
}
});
ipcMain.on('window-close', () => {
mainWindow.close();
});
2.4 预加载脚本实现
创建electron/preload.js文件,用于在渲染进程中安全地暴露Electron API:
const { contextBridge, ipcRenderer } = require('electron');
// 暴露安全的API给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
minimizeWindow: () => ipcRenderer.send('window-minimize'),
maximizeWindow: () => ipcRenderer.send('window-maximize'),
closeWindow: () => ipcRenderer.send('window-close'),
isElectron: true
});
2.5 调整package.json配置
修改package.json文件,添加Electron相关配置和脚本:
{
"name": "ruoyi",
"version": "3.9.0",
"main": "electron/main.js",
"scripts": {
"dev": "vite",
"build:prod": "vite build",
"build:stage": "vite build --mode staging",
"preview": "vite preview",
"electron:dev": "NODE_ENV=development electron .",
"electron:build": "npm run build:prod && electron-builder",
"prepare": "husky"
},
"build": {
"appId": "com.ruoyi.desktop",
"productName": "RuoYi-Vue3管理系统",
"copyright": "Copyright © 2025 若依",
"directories": {
"output": "electron_dist"
},
"files": [
"dist/**/*",
"electron/**/*"
],
"win": {
"icon": "src/assets/logo/logo.png",
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
]
},
"mac": {
"icon": "src/assets/logo/logo.png",
"target": "dmg"
},
"linux": {
"icon": "src/assets/logo/logo.png",
"target": "deb"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"installerIcon": "src/assets/logo/logo.png",
"uninstallerIcon": "src/assets/logo/logo.png",
"installerHeaderIcon": "src/assets/logo/logo.png",
"createDesktopShortcut": true,
"createStartMenuShortcut": true
}
}
}
2.6 调整Vite配置
修改vite.config.js文件,确保在开发环境下Electron能正确加载应用:
import { defineConfig, loadEnv } from 'vite'
import path from 'path'
import createVitePlugins from './vite/plugins'
// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
const env = loadEnv(mode, process.cwd())
const { VITE_APP_ENV } = env
// 判断是否为Electron开发环境
const isElectronDev = process.env.NODE_ENV === 'development' && process.env.IS_ELECTRON === 'true';
return {
base: VITE_APP_ENV === 'production' ? './' : '/',
plugins: createVitePlugins(env, command === 'build'),
resolve: {
alias: {
'~': path.resolve(__dirname, './'),
'@': path.resolve(__dirname, './src')
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
build: {
sourcemap: command === 'build' ? false : 'inline',
outDir: 'dist',
assetsDir: 'assets',
chunkSizeWarningLimit: 2000,
rollupOptions: {
output: {
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]'
}
}
},
server: {
port: 8080,
host: true,
open: !isElectronDev, // Electron开发环境下不自动打开浏览器
proxy: {
'/dev-api': {
target: 'http://localhost:8080',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/dev-api/, '')
}
}
}
}
})
三、桌面端特有功能实现
3.1 自定义窗口控制
在Vue组件中使用Electron API实现自定义窗口控制:
<template>
<div class="window-controls">
<button @click="minimizeWindow" class="control-btn">—</button>
<button @click="maximizeWindow" class="control-btn">□</button>
<button @click="closeWindow" class="control-btn">×</button>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue';
const isElectron = ref(false);
onMounted(() => {
// 检查是否在Electron环境中
isElectron.value = window.electronAPI?.isElectron || false;
});
const minimizeWindow = () => {
if (isElectron.value) {
window.electronAPI.minimizeWindow();
}
};
const maximizeWindow = () => {
if (isElectron.value) {
window.electronAPI.maximizeWindow();
}
};
const closeWindow = () => {
if (isElectron.value) {
window.electronAPI.closeWindow();
}
};
</script>
<style scoped>
.window-controls {
display: flex;
gap: 8px;
padding: 8px;
}
.control-btn {
width: 30px;
height: 30px;
border: none;
border-radius: 4px;
background-color: #f0f0f0;
cursor: pointer;
font-size: 16px;
transition: background-color 0.2s;
}
.control-btn:hover {
background-color: #e0e0e0;
}
</style>
3.2 系统托盘功能
扩展Electron主进程,添加系统托盘功能:
// 在electron/main.js中添加
const { Tray, Menu } = require('electron');
let tray = null;
function createTray() {
tray = new Tray(path.join(__dirname, '../src/assets/logo/logo.png'));
const contextMenu = Menu.buildFromTemplate([
{
label: '显示窗口',
click: () => {
mainWindow.show();
}
},
{
label: '隐藏窗口',
click: () => {
mainWindow.hide();
}
},
{ type: 'separator' },
{
label: '退出',
click: () => {
app.quit();
}
}
]);
tray.setToolTip('RuoYi-Vue3管理系统');
tray.setContextMenu(contextMenu);
// 点击托盘图标显示/隐藏窗口
tray.on('click', () => {
if (mainWindow.isVisible()) {
mainWindow.hide();
} else {
mainWindow.show();
}
});
}
// 在createWindow函数中调用
function createWindow() {
// ... 现有代码 ...
// 创建系统托盘
createTray();
}
四、应用打包与分发
4.1 打包命令
添加完成所有功能后,使用以下命令打包桌面应用:
# 构建生产版本并打包Electron应用
npm run electron:build
4.2 打包配置详解
Electron-builder的打包配置主要包括以下几个部分:
| 配置项 | 说明 |
|---|---|
| appId | 应用唯一标识 |
| productName | 应用名称 |
| copyright | 版权信息 |
| directories.output | 输出目录 |
| files | 需要打包的文件 |
| win/mac/linux | 各平台特有配置 |
| nsis | Windows安装程序配置 |
4.3 分发策略
根据目标平台的不同,打包后会生成不同类型的安装文件:
- Windows:
.exe安装程序 - macOS:
.dmg磁盘镜像 - Linux:
.deb安装包
五、常见问题解决方案
5.1 开发环境热重载
在开发过程中,为了实现Vite和Electron的同时热重载,可以使用concurrently和wait-on工具:
npm install concurrently wait-on --save-dev
修改package.json脚本:
{
"scripts": {
"electron:dev": "concurrently \"vite\" \"wait-on http://localhost:8080 && NODE_ENV=development electron .\""
}
}
5.2 跨域问题处理
在Electron环境中,可以通过主进程代理解决API跨域问题:
// 在electron/main.js中添加
const { session } = require('electron');
// 设置API请求代理
session.defaultSession.webRequest.onBeforeSendHeaders((details, callback) => {
details.requestHeaders['Origin'] = 'http://localhost:8080';
callback({ requestHeaders: details.requestHeaders });
});
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({
responseHeaders: {
...details.responseHeaders,
'Access-Control-Allow-Origin': ['http://localhost:8080'],
'Access-Control-Allow-Credentials': ['true']
}
});
});
5.3 性能优化建议
-
禁用不必要的Web功能:在Electron环境中,可以禁用一些Web特有功能,如PWA等。
-
优化资源加载:使用Electron的
webPreferences配置优化资源加载:
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
webSecurity: true,
allowRunningInsecureContent: false,
imageAnimationPolicy: 'no-animation',
backgroundThrottling: true
}
- 内存泄漏监控:使用Electron的性能监控工具:
// 在开发环境中启用性能监控
if (process.env.NODE_ENV === 'development') {
mainWindow.webContents.openDevTools({ mode: 'detach' });
setInterval(() => {
const memoryUsage = process.getHeapUsage();
console.log(`Memory usage: ${Math.round(memoryUsage.usedHeapSize / 1024 / 1024)}MB`);
}, 5000);
}
六、总结与展望
6.1 项目改造回顾
通过本文介绍的方法,我们成功将RuoYi-Vue3 Web应用改造为Electron桌面应用,主要完成了以下工作:
- 添加Electron相关依赖和配置
- 实现主进程和渲染进程通信
- 添加桌面端特有功能(窗口控制、系统托盘)
- 优化打包配置和分发策略
- 解决常见问题(热重载、跨域、性能)
6.2 未来扩展方向
-
离线数据同步:利用Electron的文件系统访问能力,实现本地数据存储和云端同步。
-
系统集成:与操作系统深度集成,如添加右键菜单、文件类型关联等。
-
多窗口管理:实现多文档界面(MDI),提升复杂操作的用户体验。
-
自动更新:集成Electron-updater,实现应用自动更新功能。
结语
通过Electron框架,我们可以快速将现有的RuoYi-Vue3 Web应用改造为功能完备的桌面应用,同时保留原有的开发流程和用户体验。这种方式不仅降低了跨平台开发的成本,还为企业级应用提供了更多可能性。希望本文介绍的方案能够帮助你顺利完成自己的跨平台项目改造!
如果觉得本文对你有帮助,请点赞、收藏并关注我们,获取更多关于RuoYi-Vue3和Electron开发的实战技巧。下期我们将带来《RuoYi-Vue3插件系统设计与实现》,敬请期待!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



