公司项目由于来不及单独做客户端了,所以想到用electron直接将前端打包程exe,dmg等格式的安装包。
由于使用的ruoyi-vue框架开发,所以这篇教程以ruoyi-vue为基础的。
环境说明
- nodejs:v16.18.1
- npm:8.19.2
- ruoyi-vue:3.8.6
环境部署
下载若依并安装依赖
ruoyi-vue:https://gitee.com/y_project/RuoYi-Vue
# 进入项目目录 cd ruoyi-ui # 安装依赖 强烈建议不要用直接使用 # cnpm 安装,会有各种诡异的 bug # 可以通过重新指定 registry 来解决 npm 安装速度慢的问题。 npm install --registry=https://registry.npmmirror.com
安装electron相关插件
# electron npm install electron # 在 Electron 应用程序中安装和管理开发者工具 npm install electron-devtools-installer # 简单的持久化数据存储库 npm install electron-store # 在 Vue CLI 项目中集成 Electron 打包和构建 npm install vue-cli-plugin-electron-builder
如果报错,大概率是网络问题。可以尝试科学上网或指定安装源:
# electron npm install electron --registry=https://registry.npmmirror.com # 在 Electron 应用程序中安装和管理开发者工具 npm install electron-devtools-installer --registry=https://registry.npmmirror.com # 简单的持久化数据存储库 npm install electron-store --registry=https://registry.npmmirror.com # 在 Vue CLI 项目中集成 Electron 打包和构建 npm install vue-cli-plugin-electron-builder --registry=https://registry.npmmirror.com
修改ruoyi-vue相关配置/代码(很重要)
在修改前建议使用git的朋友另外起一个分支,没有用git的朋友备份一份代码。
因为你的应用应该不止是提供客户端还需要提供web端,经过下面的修改操作有部分功能将会不太适合web端。切记!!
修改.env.production生产环境配置
(如果不改调用的接口的前缀将变成本地目录)
找到这段配置:
# 若依管理系统/生产环境 VUE_APP_BASE_API = '/prod-api'
如果项目web前端没有部署改为线上后端地址:
VUE_APP_BASE_API = 'http://localhost:8080'
如果项目web前端已经部署可写改为:
VUE_APP_BASE_API = 'http://IP/prod-api'
注释掉v-clipboard 文字复制剪贴
(为了解决clipboard报错)
找到:ruoyi-ui/src/directive/module/clipboard.js,然后全部注释掉。
修改 vue.config.js 配置
(不修改会找不到静态资源和接口无法访问)
位置:ruoyi-ui/vue.config.js
# 修改静态资源路径 publicPath: './', # 修改为实际接口地址 target: `http://localhost:8080`
修改路由配置(按需)
(如果出现菜单栏跳转404,部分无法跳转问题)
找到:ruoyi-ui/src/router/index.js
# 原配置 export default new Router({ mode: 'history', // 去掉url中的# scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) # 改为: # 路由模式改为hash意味着在URL中使用hash(#)来表示路由路径 export default new Router({ mode: 'hash', // 去掉url中的# scrollBehavior: () => ({ y: 0 }), routes: constantRoutes })
全局修改Cookies为localStorage(重要)
(如果不修改,登录等使用Cookies的场景将无法继续,比如登录无法跳转到主页面。)
- 全局搜索Cookies.get并替换为localStorage.getItem
- 全局搜索Cookies.set并替换为localStorage.setItem
然后找到:ruoyi-ui/src/views/login.vue
将:
localStorage.setItem("username", this.loginForm.username, { expires: 30 }); localStorage.setItem("password", encrypt(this.loginForm.password), { expires: 30 }); localStorage.setItem('rememberMe', this.loginForm.rememberMe, { expires: 30 });
替换为:
localStorage.setItem("username", this.loginForm.username); localStorage.setItem("password", encrypt(this.loginForm.password)); localStorage.setItem('rememberMe', this.loginForm.rememberMe);
也就是把过期时间删掉了。
- 全局搜索Cookies.remove并替换为localStorage.removeItem
全局修改path.resolve为path.posix.resolve
(为了解决菜单栏跳转为404的问题)
electron中的路由跳转路径解析path.resolve结果与在浏览器中的web项目解析结果不一致
path 模块的默认操作会因 Node.js 应用程序运行所在的操作系统而异。 具体来说,当在 Windows 操作系统上运行时, path模块会假定正被使用的是 Windows 风格的路径。
path.posix 属性提供对 path 方法的 POSIX 特定实现的访问。(意思就是无视操作系统的不同,统一为 POSIX方式,这样可以确保在任何系统上结果保持一致)
全局搜索path.resolve并替换为path.posix.resolve
修复无法退出登录问题
(主要修改一下退出登录后跳转的页面)
位置:ruoyi-ui/src/layout/components/Navbar.vue
找到:
async logout() { this.$confirm('确定注销并退出系统吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$store.dispatch('LogOut').then(() => { location.href = '/index'; }) }).catch(() => {}); }
修改为:
async logout() { this.$confirm('确定注销并退出系统吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.$store.dispatch('LogOut').then(() => { this.$router.push('/login') }) }).catch(() => {}); }
package.json新增electron打包配置
位置:ruoyi-ui/package.json
找到scripts,新增以下配置:
"electron:serve": "vue-cli-service electron:serve", "electron:build": "vue-cli-service electron:build", "electron:build:win32": "vue-cli-service electron:build --win --ia32"
vue.config.js添加打包配置
在module.exports中添加以下配置:(可自定义)
pluginOptions: { electronBuilder: { // preload: 'src/preload.js', nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, publish: [{ "provider": "xxxx有限公司", "url": "http://xxxxx/" }], "copyright": "Copyright © 2022", builderOptions:{ appId: 'com.ruoyi', productName: 'ruoyi', nsis:{ "oneClick": false, "guid": "idea", "perMachine": true, "allowElevation": true, "allowToChangeInstallationDirectory": true, "installerIcon": "build/app.ico", "uninstallerIcon": "build/app.ico", "installerHeaderIcon": "build/app.ico", "createDesktopShortcut": true, "createStartMenuShortcut": true, "shortcutName": "若依管理系統" }, win: { "icon": "build/app.ico", "target": [ { "target": "nsis", //使用nsis打成安装包,"portable"打包成免安装版 "arch": [ "ia32", //32位 "x64" //64位 ] } ] }, }, // preload: path.join(__dirname, "/dist_electron/preload.js"), }, },
electron配置
新增background.js
在src新建background.js
(background.js名字不可修改,否则会报错)
'use strict' import { app, protocol, BrowserWindow, ipcMain } from 'electron' import { createProtocol } from 'vue-cli-plugin-electron-builder/lib' import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer' const isDevelopment = process.env.NODE_ENV !== 'production' const Store = require('electron-store'); // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ { scheme: 'app', privileges: { secure: true, standard: true } } ]) async function createWindow() { // Create the browser window. const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { // Use pluginOptions.nodeIntegration, leave this alone // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info contextIsolation:false, //上下文隔离 enableRemoteModule: true, //启用远程模块 nodeIntegration: true, //开启自带node环境 webviewTag: true, //开启webview webSecurity: false, allowDisplayingInsecureContent: true, allowRunningInsecureContent: true } }) win.maximize() win.show() win.webContents.openDevTools() ipcMain.on('getPrinterList', (event) => { //主线程获取打印机列表 win.webContents.getPrintersAsync().then(data=>{ win.webContents.send('getPrinterList', data); }); //通过webContents发送事件到渲染线程,同时将打印机列表也传过去 }); if (process.env.WEBPACK_DEV_SERVER_URL) { // Load the url of the dev server if in development mode await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL) if (!process.env.IS_TEST) win.webContents.openDevTools() } else { createProtocol('app') // Load the index.html when not in development win.loadURL('app://./index.html') } } // Quit when all windows are closed. app.on('window-all-closed', () => { // On macOS it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) createWindow() }) // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. app.on('ready', async () => { Store.initRenderer(); if (isDevelopment && !process.env.IS_TEST) { // Install Vue Devtools try { await installExtension(VUEJS_DEVTOOLS) } catch (e) { console.error('Vue Devtools failed to install:', e.toString()) } } createWindow() }) // Exit cleanly on request from parent process in development mode. if (isDevelopment) { if (process.platform === 'win32') { process.on('message', (data) => { if (data === 'graceful-exit') { app.quit() } }) } else { process.on('SIGTERM', () => { app.quit() }) } }
引入background.js
位置:ruoyi-ui/package.json
新增:"main": "background.js",
执行打包
npm run electron:build
打包完成后会生成:dist_electron目录
其他
结束了,有问题可留言讨论。欢迎评论,点赞,收藏。