Vue 转 EXE 完整实战教程
大约 8 分钟
Vue 转 EXE 完整实战教程
📖 概述
本文档详细介绍如何将 Vue.js 项目转换为 Windows EXE 可执行文件,使用 Electron 技术栈实现跨平台桌面应用。
本教程特色:
- ✅ 基于真实项目(青阳大屏系统)的实战经验
- ✅ 完整的配置文件示例和详细说明
- ✅ 涵盖从开发到打包的全流程
- ✅ 提供可复用的配置模板
- ✅ 详细的问题排查和解决方案
适用场景:
- 需要将 Web 应用转换为桌面应用
- 需要离线运行的大屏展示系统
- 需要系统级权限的应用程序
- 需要与本地服务(如 MySQL、Redis)集成的应用
🛠️ 技术栈
核心技术
- Vue.js 2.x - 前端框架(本教程基于 Vue 2.6.14)
- Electron - 桌面应用框架(推荐 13.x+)
- Electron Builder - 打包工具
- Vue CLI Plugin Electron Builder - Vue 集成插件
项目依赖(青阳大屏系统实例)
{
"name": "qyscreen",
"version": "3.9.0",
"description": "青阳大屏后台管理",
"main": "electron/main.js",
"dependencies": {
"vue": "2.6.14",
"element-ui": "2.15.14",
"axios": "0.28.1",
"echarts": "5.4.0",
"ol": "^6.15.1"
},
"devDependencies": {
"electron": "^13.6.9",
"electron-builder": "^23.0.3",
"concurrently": "^7.0.0",
"cross-env": "^7.0.3",
"wait-on": "^6.0.1"
}
}
🚀 项目初始化
1. 现有 Vue 项目添加 Electron
如果你已有 Vue 项目,执行以下命令添加 Electron 支持:
# 安装 Vue CLI Electron Builder 插件
vue add electron-builder
# 选择 Electron 版本(推荐最新稳定版)
# 选择是否使用 TypeScript(根据项目需要)
2. 全新项目创建
# 创建 Vue 项目
vue create my-electron-app
cd my-electron-app
# 添加 Electron 支持
vue add electron-builder
3. 项目结构
添加 Electron 后的项目结构:
my-electron-app/
├── src/ # Vue 源码
│ ├── components/
│ ├── views/
│ ├── App.vue
│ └── main.js
├── electron/ # Electron 相关文件
│ ├── main.js # 主进程文件
│ ├── preload.js # 预加载脚本
│ └── icon.ico # 应用图标
├── dist_electron/ # 打包输出目录
├── package.json
└── vue.config.js
⚙️ 核心配置
1. package.json 配置
基础配置
{
"name": "qyscreen",
"version": "3.9.0",
"description": "青阳大屏后台管理",
"author": "若依",
"license": "MIT",
"main": "electron/main.js",
"homepage": "./",
"scripts": {
"dev": "vue-cli-service serve",
"build:prod": "vue-cli-service build",
"electron:dev": "concurrently \"cross-env NODE_ENV=development npm run dev\" \"wait-on http://localhost:9527 && cross-env NODE_ENV=development electron .\"",
"electron:build": "cross-env IS_ELECTRON=true npm run build:prod && electron-builder",
"electron:build:win": "cross-env IS_ELECTRON=true ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true npm run build:prod && electron-builder --win --x64 --config.compression=store"
}
}
关键配置说明
| 配置项 | 说明 | 重要性 |
|---|---|---|
main | 指定 Electron 主进程入口文件 | ⭐⭐⭐⭐⭐ |
homepage | 设置为 ./ 确保资源路径正确 | ⭐⭐⭐⭐⭐ |
electron:dev | 开发模式:同时启动 Vue 开发服务器和 Electron | ⭐⭐⭐⭐ |
electron:build:win | 生产打包:构建 Vue 项目并打包为 Windows EXE | ⭐⭐⭐⭐⭐ |
IS_ELECTRON=true | 环境变量标识,用于区分 Electron 和 Web 环境 | ⭐⭐⭐⭐ |
--config.compression=store | 不压缩,加快打包速度(开发阶段) | ⭐⭐⭐ |
2. vue.config.js 配置
完整配置示例(青阳大屏系统)
const { defineConfig } = require('@vue/cli-service')
const path = require('path')
module.exports = defineConfig({
transpileDependencies: true,
// 公共路径配置 - 关键!确保打包后资源路径正确
publicPath: process.env.IS_ELECTRON ? './' : '/',
// 输出目录
outputDir: 'dist',
// 静态资源目录
assetsDir: 'static',
// 生产环境 source map
productionSourceMap: false,
// Electron 配置
pluginOptions: {
electronBuilder: {
// 主进程文件
mainProcessFile: 'electron/main.js',
// 渲染进程文件(可选)
rendererProcessFile: 'src/main.js',
// 预加载脚本
preload: 'electron/preload.js',
// Node 集成(推荐关闭,使用 preload 脚本)
nodeIntegration: false,
// 打包配置
builderOptions: {
appId: 'com.qingyang.screen',
productName: '青阳大屏系统',
copyright: 'Copyright © 2024',
// 应用图标
icon: 'electron/icon.ico',
// Windows 配置
win: {
target: [
{
target: 'nsis', // 安装包格式
arch: ['x64'] // 64位
},
{
target: 'portable', // 便携版
arch: ['x64']
}
],
icon: 'electron/icon.ico',
artifactName: '${productName}-${version}-${arch}.${ext}'
},
// NSIS 安装器配置
nsis: {
oneClick: false, // 允许自定义安装
allowElevation: true, // 允许提升权限
allowToChangeInstallationDirectory: true, // 允许选择安装目录
createDesktopShortcut: true, // 创建桌面快捷方式
createStartMenuShortcut: true, // 创建开始菜单快捷方式
shortcutName: '青阳大屏系统', // 快捷方式名称
include: 'build/installer.nsh', // 自定义安装脚本(可选)
installerIcon: 'electron/icon.ico', // 安装程序图标
uninstallerIcon: 'electron/icon.ico', // 卸载程序图标
installerHeaderIcon: 'electron/icon.ico', // 安装程序头部图标
deleteAppDataOnUninstall: false // 卸载时不删除用户数据
},
// 文件包含配置
files: [
'dist/**/*',
'electron/main.js',
'electron/preload.js',
'electron/icon.ico',
'public/kiosk-config.json', // Kiosk配置文件
'!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme}',
'!**/node_modules/*/{test,__tests__,tests,powered-test,example,examples}',
'!**/node_modules/*.d.ts',
'!**/node_modules/.bin',
'!**/*.{iml,o,hprof,orig,pyc,pyo,rbc,swp,csproj,sln,xproj}',
'!.editorconfig',
'!**/._*',
'!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,.gitignore,.gitattributes}',
'!**/{__pycache__,thumbs.db,.flowconfig,.idea,.vs,.nyc_output}',
'!**/{appveyor.yml,.travis.yml,circle.yml}',
'!**/{npm-debug.log,yarn.lock,.yarn-integrity,.yarn-metadata.json}'
],
// 额外资源(复制到安装目录)
extraResources: [
{
from: 'public/kiosk-config.json',
to: 'kiosk-config.json'
}
],
// 目录配置
directories: {
output: 'dist_electron', // 输出目录
buildResources: 'build' // 构建资源目录
},
// 压缩配置
compression: 'normal', // 压缩级别: store, normal, maximum
// 发布配置(可选)
publish: null
},
// 外部模块(不打包进 asar)
externals: ['serialport', 'sqlite3'],
// 自定义协议
customFileProtocol: './'
}
},
// 开发服务器配置
devServer: {
port: 9527,
host: 'localhost',
open: false,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
},
// Webpack 配置
configureWebpack: {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
// 性能优化
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
libs: {
name: 'chunk-libs',
test: /[\\/]node_modules[\\/]/,
priority: 10,
chunks: 'initial'
},
elementUI: {
name: 'chunk-elementUI',
priority: 20,
test: /[\\/]node_modules[\\/]_?element-ui(.*)/
},
commons: {
name: 'chunk-commons',
test: path.resolve(__dirname, 'src/components'),
minChunks: 3,
priority: 5,
reuseExistingChunk: true
}
}
}
}
}
})
关键配置说明
| 配置项 | 说明 | 注意事项 |
|---|---|---|
publicPath | 资源公共路径 | Electron环境必须设置为 ./ |
productName | 应用程序名称 | 显示在标题栏和安装程序中 |
appId | 应用唯一标识 | 格式: com.company.app |
icon | 应用图标 | Windows使用.ico格式,至少256x256 |
nsis.oneClick | 是否一键安装 | false允许用户选择安装路径 |
files | 打包文件 | 排除不必要文件减小体积 |
extraResources | 额外资源 | 配置文件等需要外部访问的资源 |
compression | 压缩级别 | store(不压缩)、normal、maximum |
🔧 主进程开发
1. electron/main.js - 基础主进程文件
const { app, BrowserWindow, Menu } = require('electron')
const path = require('path')
const isDevelopment = process.env.NODE_ENV !== 'production'
let mainWindow = null
// 创建主窗口
function createWindow() {
// 获取屏幕尺寸
const { screen } = require('electron')
const primaryDisplay = screen.getPrimaryDisplay()
const { width, height } = primaryDisplay.workAreaSize
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
webSecurity: true
},
icon: path.join(__dirname, 'icon.ico') // 应用图标
})
// 加载应用
if (isDevelopment) {
// 开发模式:加载开发服务器
mainWindow.loadURL('http://localhost:8080')
// 打开开发者工具
mainWindow.webContents.openDevTools()
} else {
// 生产模式:加载打包后的文件
mainWindow.loadFile(path.join(__dirname, '../dist/index.html'))
}
// 设置菜单
Menu.setApplicationMenu(null) // 隐藏菜单栏
// 窗口关闭事件
mainWindow.on('closed', () => {
mainWindow = null
})
}
// 应用就绪时创建窗口
app.whenReady().then(async () => {
createWindow()
})
// 所有窗口关闭时退出应用
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
// 应用激活时重新创建窗口
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
2. electron/preload.js - 预加载脚本
const { contextBridge, ipcRenderer } = require('electron')
// 暴露安全的 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
// 获取平台信息
platform: process.platform,
// 标识这是 Electron 环境
isElectron: true,
// 版本信息
versions: {
node: process.versions.node,
chrome: process.versions.chrome,
electron: process.versions.electron
}
})
🎨 Vue 组件集成
1. 检测 Electron 环境
// 在 Vue 组件中检测 Electron 环境
export default {
data() {
return {
isElectron: false
}
},
mounted() {
this.checkEnvironment()
},
methods: {
checkEnvironment() {
// 检测是否在 Electron 环境中运行
this.isElectron = window.electronAPI && window.electronAPI.isElectron
if (this.isElectron) {
console.log('运行在 Electron 环境')
console.log('版本信息:', window.electronAPI.versions)
} else {
console.log('运行在浏览器环境')
}
}
}
}
2. 基础窗口控制组件
<template>
<div class="app-info" v-if="isElectron">
<p>运行环境: Electron</p>
<p>Node.js: {{ versions.node }}</p>
<p>Chrome: {{ versions.chrome }}</p>
<p>Electron: {{ versions.electron }}</p>
</div>
</template>
<script>
export default {
name: 'AppInfo',
data() {
return {
isElectron: false,
versions: {}
}
},
mounted() {
if (window.electronAPI && window.electronAPI.isElectron) {
this.isElectron = true
this.versions = window.electronAPI.versions
}
}
}
</script>
📦 打包部署
1. 开发模式运行
# 启动开发模式(热重载)
npm run electron:dev
# 或者
npm run electron:serve
2. 生产环境打包
# 构建生产版本
npm run electron:build
# 指定平台打包
npm run electron:build -- --win
npm run electron:build -- --mac
npm run electron:build -- --linux
3. 打包输出
打包完成后,输出文件位于 dist_electron/ 目录:
dist_electron/
├── win-unpacked/ # Windows 未打包版本
├── Your App Setup.exe # Windows 安装程序
├── Your App.exe # Windows 可执行文件
└── latest.yml # 更新配置文件
🔧 常见问题解决
1. 白屏问题
问题:打包后的应用启动显示白屏
解决方案:
// 在 vue.config.js 中设置 publicPath
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
pluginOptions: {
electronBuilder: {
builderOptions: {
// 确保文件路径正确
files: [
'dist/**/*',
'node_modules/**/*'
]
}
}
}
}
2. 路由问题
问题:使用 Vue Router 时,刷新页面出现 404
解决方案:
// router/index.js - 使用 hash 模式
const router = new VueRouter({
mode: 'hash', // 使用 hash 模式而不是 history 模式
base: process.env.BASE_URL,
routes
})
3. 资源加载问题
问题:图片、字体等静态资源无法加载
解决方案:
/* 使用相对路径 */
/* 错误写法 */
background-image: url('/assets/images/bg.jpg');
/* 正确写法 */
background-image: url('./assets/images/bg.jpg');
/* 或者 */
background-image: url('~@/assets/images/bg.jpg');
4. 开发者工具问题
问题:生产环境中意外打开了开发者工具
解决方案:
// electron/main.js
if (isDevelopment) {
// 只在开发模式下打开开发者工具
mainWindow.webContents.openDevTools()
}
// 禁用右键菜单(可选)
mainWindow.webContents.on('context-menu', (e) => {
if (!isDevelopment) {
e.preventDefault()
}
})
🚀 性能优化
1. 减小包体积
// vue.config.js - 排除不必要的文件
builderOptions: {
files: [
'dist/**/*',
'node_modules/**/*',
'!node_modules/**/{README.md,CHANGELOG.md,LICENSE}',
'!node_modules/**/test/**/*',
'!node_modules/**/*.d.ts'
]
}
2. 启用代码分割
// vue.config.js
module.exports = {
configureWebpack: {
optimization: {
splitChunks: {
chunks: 'all'
}
}
}
}
📋 部署清单
开发阶段
打包阶段
部署阶段
📚 扩展资源
总结:这是一个通用的 Vue 转 EXE 基础教程,涵盖了从项目初始化到打包部署的完整流程。掌握这些基础知识后,就可以根据具体需求进行定制化开发,比如添加 Kiosk 模式等高级功能。