Vue 转 EXE 完整实战教程

lishihuan大约 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 模式等高级功能。