Vue3.2 项目打包成 Electron 桌面应用

本文将详细介绍如何将基于 Vue3.2 的项目打包成 Electron 桌面应用。通过结合 Electron 和 Vue CLI 工具链,可以轻松实现跨平台桌面应用的开发与发布。

1. 项目结构说明

项目主要分为以下几个部分:

  • electron/main.js:Electron 主进程文件。
  • electron/preload.js:Electron 预加载脚本。
  • package.json:项目配置文件,包含 Electron 相关依赖和脚本。
  • .env 和 .env.electron:环境变量配置文件,分别用于普通模式和 Electron 模式。
  • vue.config.js:Vue CLI 的配置文件,用于优化构建和资源路径。
  • router.ts:Vue 路由配置文件,支持 hash 和 history 模式切换。

2. 代码详解

javascript 复制代码
npm install electron electron-builder cross-env --save-dev

2.1 electron/main.js

主进程文件负责创建窗口并加载 Vue 应用:

javascript 复制代码
const { app, BrowserWindow, globalShortcut, Menu } = require("electron");
const path = require("path");

let mainWindow;

// 捕获未处理的异常
process.on("uncaughtException", (error) => {
  console.error("Uncaught Exception:", error);
});

process.on("unhandledRejection", (reason, promise) => {
  console.error("Unhandled Rejection at:", promise, "reason:", reason);
});

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    icon: path.join(__dirname, "src", "assets", "logo_32.ico"),  // 设置窗口图标 尺寸:32*32
    images: true, // 启用图像支持
    show: false, // 初始时不显示窗口,避免闪烁
    // frame: false, // 隐藏默认的窗口边框和标题栏
    // fullscreen: true, // 启动时全屏
    webPreferences: {
      preload: path.join(__dirname, "preload.js"), // 预加载脚本(可选)
      nodeIntegration: true, // 启用 Node.js 集成(根据需要开启)
      // 添加以下配置解决媒体自动播放问题
      webSecurity: false, // 禁用同源策略(开发时可关闭,生产环境慎用)
      autoplayPolicy: "no-user-gesture-required", // 允许自动播放
      contextIsolation: false, // 必须为false才能访问全局变量
    },
  });

  // 加载 Vue 项目的生产构建文件
  if (process.env.NODE_ENV === "development") {
    mainWindow.loadURL("http://localhost:3000"); // 开发环境(Vue 开发服务器)
  } else {
    mainWindow.loadFile(path.join(__dirname, "../dist/index.html")); // 生产环境
  }

  // 窗口最大化
  mainWindow.maximize();

  // 显示窗口(在最大化后显示)
  mainWindow.show();

  // 隐藏菜单栏
  Menu.setApplicationMenu(null);

  // 打开开发者工具(开发时可以打开)
  // mainWindow.webContents.openDevTools();

  // 打开调试工具
  globalShortcut.register("CommandOrControl+Shift+I", () => {
    mainWindow.webContents.openDevTools();
  });

  // 切换全屏
  globalShortcut.register("CommandOrControl+Alt+Q", () => {
    if (mainWindow) {
      const isFullScreen = mainWindow.isFullScreen();
      mainWindow.setFullScreen(!isFullScreen);
    }
  });

  // 返回上一页
  globalShortcut.register("CommandOrControl+Left", () => {
    if (mainWindow) {
      const history = mainWindow.webContents.navigationHistory;
      if (history.canGoBack()) {
        history.goBack();
      }
    }
  });

  // 刷新页面
  globalShortcut.register("CommandOrControl+R", () => {
    if (mainWindow) {
      mainWindow.webContents.reload();
    }
  });

  mainWindow.on("closed", () => {
    mainWindow = null;
  });
}

app.whenReady().then(() => {
  createWindow();

  // 创建自定义菜单
  // const menuTemplate = [
  //   {
  //     label: "操作",
  //     submenu: [
  //       { type: "separator" },
  //       { label: "切换全屏", role: "togglefullscreen" },
  //       { type: "separator" },
  //       {
  //         label: "返回上一页",
  //         accelerator: "CmdOrCtrl+Left",
  //         click: () => {
  //           if (mainWindow && mainWindow.webContents.canGoBack()) {
  //             mainWindow.webContents.goBack();
  //           }
  //         },
  //       },
  //     ],
  //   },
  // ];

  // // 根据模板创建菜单
  // const menu = Menu.buildFromTemplate(menuTemplate);

  // // 设置应用菜单
  // Menu.setApplicationMenu(menu);

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

// 退出时注销快捷键
app.on("will-quit", () => {
  globalShortcut.unregisterAll();
});

2.2 electron/preload.js

javascript 复制代码
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electronAPI', {
  send: (channel, data) => ipcRenderer.send(channel, data),
  receive: (channel, func) => ipcRenderer.on(channel, (event, ...args) => func(...args)),
});

2.3 package.json

配置了 Electron 相关的脚本和依赖:

javascript 复制代码
{
  "name": "saas_system",
  "version": "0.1.35",
  "private": true,
  "main": "electron/main.js",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "test:unit": "vue-cli-service test:unit",
    "lint": "vue-cli-service lint",
    "start": "electron .",
    "build:electron": "vue-cli-service build --mode electron",
    "electron:serve": "vue-cli-service serve --mode development && electron .",
    "electron:build": "vue-cli-service build --mode electron && electron-builder"
  },
  "dependencies": {
    "electron": "^35.1.3",
    "electron-builder": "^26.0.12"
  },
  "build": {
    "appId": "com.example.myapp",
    "productName": "myapp",
    "files": [
      "dist/**/*",
      "electron/main.js",
      "src/assets/logo.ico" // 尺寸:256*256
    ],
    "win": {
      "target": "nsis",
      "icon": "src/assets/logo.ico" // 尺寸:256*256
    },
    "mac": {
      "target": "dmg"
    },
    "linux": {
      "target": "AppImage"
    }
  }
}

2.4 .env 和 .env.electron

分别定义了普通模式和 Electron 模式的环境变量:

.env 文件

javascript 复制代码
VUE_APP_ROUTER_MODE=history
VUE_APP_PUBLIC_PATH=/

.env.electron 文件

javascript 复制代码
VUE_APP_ROUTER_MODE=hash
VUE_APP_PUBLIC_PATH=./

2.5 vue.config.js

动态生成资源路径前缀:

javascript 复制代码
const productionGzipExtensions = ["js", "css"];

module.exports = {
  publicPath: process.env.VUE_APP_PUBLIC_PATH || "/",
  configureWebpack: {
    devtool: "source-map",
    output: {
      filename: `${getAssetsPath()}js/[name].${Timestamp}.js`,
      chunkFilename: `${getAssetsPath()}js/[name].${Timestamp}.js`,
    },
  },
  css: {
    extract: {
      filename: `${getAssetsPath()}css/[name].${Timestamp}.css`,
      chunkFilename: `${getAssetsPath()}css/[name].${Timestamp}.css`,
    },
  },
};

2.6 router.ts

路由配置支持 hash 和 history 模式切换:

javascript 复制代码
import { createRouter, createWebHashHistory, createWebHistory } from "vue-router";

const router = createRouter({
  history: process.env.VUE_APP_ROUTER_MODE === 'hash'
    ? createWebHashHistory(process.env.BASE_URL)
    : createWebHistory(process.env.BASE_URL),
  routes,
});

router.beforeResolve((to, from, next) => {
  const isFileProtocol = window.location.protocol === "file:";
  let token = localStorage.getItem("token");

  if (!token) {
    if (isFileProtocol) {
      next("./official_website?redirect=" + encodeURIComponent(to.path));
    } else {
      next("/official_website?redirect=" + encodeURIComponent(to.path));
    }
  } else {
    next();
  }
});

3. 打包流程

安装依赖:

javascript 复制代码
npm install

启动开发模式:

javascript 复制代码
npm run electron:serve

打包 Electron 应用:

javascript 复制代码
npm run electron:build

生成的安装包会存放在 release 文件夹中。

4. 总结

通过上述步骤,您可以成功将 Vue3.2 项目打包为 Electron 桌面应用。Electron 提供了强大的跨平台能力,而 Vue 则让前端开发更加高效。希望本文对您有所帮助!

相关推荐
编程毕设1 小时前
【开题报告+论文+源码】基于SpringBoot+Vue的招聘管理系统的设计与实现
vue.js·spring boot·后端
magic 2451 小时前
ES6变量声明:let、var、const全面解析
前端·javascript·ecmascript·es6
好_快1 小时前
Lodash源码阅读-dropWhile
前端·javascript·源码阅读
好_快1 小时前
Lodash源码阅读-dropRightWhile
前端·javascript·源码阅读
二川bro2 小时前
Vue 项目中 package.json 文件的深度解析
前端·vue.js·json
请叫我欧皇i2 小时前
vue2使用ezuikit-js播放萤石视频
开发语言·javascript·ecmascript
IT专家-大狗3 小时前
Google Chrome Canary版官方下载及安装教程【适用于开发者与进阶用户】
开发语言·javascript·chrome·ecmascript
喜欢便码7 小时前
JS小练习0.1——弹出姓名
java·前端·javascript
chase。7 小时前
【学习笔记】MeshCat: 基于three.js的远程可控3D可视化工具
javascript·笔记·学习
千野竹之卫8 小时前
3D珠宝渲染用什么软件比较好?渲染100邀请码1a12
开发语言·前端·javascript·3d·3dsmax