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

news2025/4/8 10:08:27

本文将详细介绍如何将基于 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. 代码详解

npm install electron electron-builder cross-env --save-dev

2.1 electron/main.js

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

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

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 相关的脚本和依赖:

{
  "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 文件

VUE_APP_ROUTER_MODE=history
VUE_APP_PUBLIC_PATH=/

.env.electron 文件

VUE_APP_ROUTER_MODE=hash
VUE_APP_PUBLIC_PATH=./

2.5 vue.config.js

动态生成资源路径前缀:

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 模式切换:

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. 打包流程

安装依赖:

npm install

启动开发模式:

npm run electron:serve

打包 Electron 应用:

npm run electron:build

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

4. 总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2330399.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ubuntu 20.04 编译和运行SC-LeGo-LOAM

1.搭建文件目录和clone代码 mkdir -p SC-LeGo-LOAM/src cd SC-LeGo-LOAM/src git clone https://github.com/AbangLZU/SC-LeGO-LOAM.git cd .. 2.修改代码 需要注意的是原作者使用的是Ouster OS-64雷达,需要更改utility.h文件中适配自己的雷达类型,而…

CentOS 7安装hyperscan

0x00 前言 HyperScan是一款由Intel开发的高性能正则表达式匹配库,专为需要快速处理大量数据流的应用场景而设计。它支持多平台运行,包括Linux、Windows和macOS等操作系统,并针对x86架构进行了优化,以提供卓越的性能表现。HyperSc…

UE5 Simulation Stage

首先将Grid2D创建出来,然后设置值,Grid2D类似于在Niagara系统中的RenderTarget2D,可以进行绘制,那么设置大小为512 * 512 开启Niagara粒子中的Simulation Stage 然后开始编写我们的自定义模块 模块很简单,TS就是Textur…

Swift 解 LeetCode 250:搞懂同值子树,用递归写出权限系统检查器

文章目录 前言问题描述简单说:痛点分析:到底难在哪?1. 子树的概念搞不清楚2. 要不要“递归”?递归从哪开始?3. 怎么“边遍历边判断”?这套路不熟 后序遍历 全局计数器遍历过程解释一下:和实际场…

增益调度控制 —— 理论、案例与交互式 GUI 实现

目录 增益调度控制 —— 理论、案例与交互式 GUI 实现一、引言二、增益调度控制的基本原理三、数学模型与公式推导四、增益调度控制的优势与局限4.1 优势4.2 局限五、典型案例分析5.1 案例一:航空飞行控制中的增益调度5.2 案例二:发动机推力控制中的增益调度5.3 案例三:化工…

关于OEC/OEC-turbo刷机问题的一些解决方法(2)——可能是终极解决方法了

前面写了两篇关于OEC/OEC-turbo刷机问题的文章了,从刷机过程、刷机中遇到的问题,以及遇到最多但始终无法有效解决的下载boot失败的问题的剖析,最近确实也做了一些工作,虽然没有最终解决,但也算是这系列文章里面阶段性的…

瓦片数据合并方法

影像数据 假如有两份影像数据 1.全球底层影像0-5级别如下: 2.局部高清影像数据级别9-14如下: 合并方法 将9-14文件夹复制到全球底层0-5的目录下 如下: 然后合并xml文件 使得Tileset设置到最高级(包含所有级别)&…

第16届蓝桥杯单片机模拟试题Ⅰ

试题 代码 sys.h #ifndef __SYS_H__ #define __SYS_H__#include <STC15F2K60S2.H> //onewire.c float getT(); //sys.c extern unsigned char UI; extern bit touch_mode; extern float jiaozhun; extern float canshu; extern float temper; void init74hc138(unsigned…

mac 卸载流氓软件安全助手

之前个人电脑在公司使用过一段时间&#xff0c;为了使用网线联网安装了公司指定的 联软上网助手&#xff0c;谁知安装容易卸载难&#xff0c;后来找运维来卸载&#xff0c;输入管理员密码后&#xff0c;也无反应&#xff0c;最后不了了之了&#xff0c;这个毒瘤软件长期在后台驻…

⭐算法OJ⭐滑动窗口最大值【双端队列(deque)】Sliding Window Maximum

文章目录 双端队列(deque)详解基本特性常用操作1. 构造和初始化2. 元素访问3. 修改操作4. 容量操作 性能特点时间复杂度&#xff1a;空间复杂度&#xff1a; 滑动窗口最大值题目描述方法思路解决代码 双端队列(deque)详解 双端队列(deque&#xff0c;全称double-ended queue)是…

沧州铁狮子

又名“镇海吼”&#xff0c;是中国现存年代最久、形体最大的铸铁狮子&#xff0c;具有深厚的历史文化底蕴和独特的艺术价值。以下是关于沧州铁狮子的详细介绍&#xff1a; 历史背景 • 铸造年代&#xff1a;沧州铁狮子铸造于后周广顺三年&#xff08;953年&#xff09;&#…

Python•判断循环

ʕ⸝⸝⸝˙Ⱉ˙ʔ ♡ 判断🍰常用的判断符号(比较运算符)andor括号notin 和 not inif-elif-else循环🍭计数循环 forrange()函数简易倒计时enumerate()函数zip()函数遍历列表遍历元组遍历字符串遍历字典条件循环 while提前跳转 continue跳出循环 break能量站😚判断🍰 …

【力扣hot100题】(060)分割回文串

每次需要判断回文串&#xff0c;这点比之前几题回溯题目复杂一些。 还有我怎么又多写了循环…… class Solution { public:vector<vector<string>> result;string s;bool palindromic(string s){for(int i0;i<s.size()/2;i) if(s[i]!s[s.size()-1-i]) return …

C++---day7

#include <iostream> #include <cstring> #include <cstdlib> #include <unistd.h> #include <sstream> #include <vector> #include <memory>using namespace std;class Stu { private:public:};// 自定义 vector 类&#xff0c;重…

SvelteKit 最新中文文档教程(17)—— 仅服务端模块和快照

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

flink 增量快照同步文件引用关系和恢复分析

文章目录 文件引用分析相关代码分析从state 恢复&#xff0c;以rocksdb为例不修改并行度修改并行度keyGroupRange过程问题 文件引用分析 每次生成的checkpoint 里都会有所有文件的引用信息 问题&#xff0c;引用分析里如何把f1,f2去掉了&#xff0c;可以参考下面的代码&#…

c++概念—内存管理

文章目录 c内存管理c/c的内存区域划分回顾c语言动态内存管理c动态内存管理new和delete的使用new和delete的底层逻辑operator new函数和operator delete函数new和delete的实现操作方式不匹配的情况定位new new/delete和malloc/free的区别 c内存管理 在以往学习c语言的过程中&…

无人机双频技术及底层应用分析!

一、双频技术的核心要点 1. 频段特性互补 2.4GHz&#xff1a;穿透力强、传输距离远&#xff08;可达5公里以上&#xff09;&#xff0c;适合复杂环境&#xff08;如城市、建筑物密集区&#xff09;&#xff0c;但易受Wi-Fi、蓝牙等设备的干扰。 5.8GHz&#xff1a;带宽更…

【电视软件】小飞电视v2.7.0 TV版-清爽无广告秒换台【永久更新】

软件介绍 小飞电视是一款电视端的直播软件&#xff0c;无需二次付费和登录&#xff0c;资源丰富&#xff0c;高清流畅。具备开机自启、推送功能、自定义直播源、个性化设置及节目预告等实用功能&#xff0c;为用户带来良好的观看体验。基于mytv开源项目二改&#xff0c;涵盖央…

Valgrind——内存调试和性能分析工具

文章目录 一、Valgrind 介绍二、Valgrind 功能和使用1. 主要功能2. 基本用法2.1 常用选项2.2 内存泄漏检测2.3 详细报告2.4 性能分析2.5 多线程错误检测 三、在 Ubuntu 上安装 Valgrind四、示例1. 检测内存泄漏2. 使用未初始化的内存3. 内存读写越界4. 综合错误 五、工具集1. M…