当前位置: 首页 > news >正文

Electron+Vite+Vue3:从零到一构建现代化桌面应用

1. 为什么选择Electron+Vite+Vue3组合?

在开始动手之前,我们先聊聊为什么这个技术组合如此受欢迎。我最初接触Electron开发时,用的是Webpack+Vue2的组合,每次保存代码都要等上好几秒才能看到效果,调试起来特别痛苦。后来尝试了Vite+Vue3,开发体验直接提升了好几个档次。

速度优势是Vite最明显的特性。传统的打包工具需要先打包整个应用才能启动开发服务器,而Vite直接利用浏览器原生ES模块支持,启动时间几乎可以忽略不计。在我的MacBook Pro上,一个中等规模的Electron项目用Webpack启动要15秒左右,而Vite只需要不到1秒。

Vue3的组合式API让代码组织更加灵活。特别是在Electron开发中,我们经常需要处理各种原生事件和状态管理,组合式API能让我们把相关逻辑集中在一起,而不是分散在多个选项块中。比如窗口大小变化的响应逻辑,可以封装成一个独立的useWindowSize组合函数。

Electron本身则解决了跨平台桌面应用的核心需求。我做过一个数据可视化工具,需要读取本地文件系统并展示复杂图表。用纯Web技术无法直接访问文件系统,而用传统原生开发又太复杂。Electron完美地结合了两者的优势,让我能用熟悉的Web技术实现桌面应用功能。

2. 环境准备与项目初始化

2.1 基础环境配置

首先确保你的开发环境满足以下要求:

  • Node.js 18.x或更高版本(推荐使用nvm管理Node版本)
  • npm 8.x或更高版本(或使用yarn、pnpm)
  • 一个顺手的代码编辑器(VSCode是我的首选)

建议先配置好国内镜像源,可以大幅提升依赖安装速度:

npm config set registry https://registry.npmmirror.com/

2.2 使用electron-vite创建项目

electron-vite是一个专门为Electron优化的构建工具,它简化了配置过程。我们用它来初始化项目:

npm create @quick-start/electron my-electron-app

创建过程中会有几个选项需要选择:

  1. 选择框架时,选Vue
  2. TypeScript按需选择(本文示例用JavaScript)
  3. 建议启用Electron更新插件
  4. 国内用户一定要开启镜像代理

初始化完成后,目录结构是这样的:

my-electron-app ├── src │ ├── main # 主进程代码 │ ├── preload # 预加载脚本 │ └── renderer # 渲染进程(Vue项目) ├── electron.vite.config.mjs # 构建配置 └── package.json

2.3 启动开发模式

进入项目目录并安装依赖:

cd my-electron-app npm install

然后修改package.json,在dev脚本后添加--watch参数以启用主进程热更新:

"scripts": { "dev": "electron-vite dev --watch" }

现在运行开发服务器:

npm run dev

你会看到一个Electron窗口弹出,里面是Vue的欢迎页面。试着修改src/renderer/App.vue文件,保存后能看到即时更新的效果。

3. 核心概念与进程通信

3.1 Electron的进程模型

Electron应用由三种进程组成:

  1. 主进程:每个应用只有一个,负责创建窗口和管理应用生命周期
  2. 渲染进程:每个窗口对应一个,负责展示Web内容
  3. 预加载脚本:在渲染进程加载前执行,桥接主进程和渲染进程

理解这个模型很重要。我刚开始时经常混淆各个进程的能力边界,比如试图在渲染进程直接调用Node.js API,结果遇到各种问题。

3.2 进程间通信实践

让我们实现一个实用功能:在Vue组件中点击按钮,让主进程弹出一个原生对话框。

首先在预加载脚本(src/preload/index.js)中暴露API:

const { contextBridge, ipcRenderer } = require('electron') contextBridge.exposeInMainWorld('electronAPI', { openDialog: () => ipcRenderer.invoke('dialog:open') })

然后在主进程(src/main/index.js)中添加处理程序:

const { ipcMain, dialog } = require('electron') ipcMain.handle('dialog:open', async () => { const { filePaths } = await dialog.showOpenDialog({ properties: ['openFile'] }) return filePaths[0] || null })

最后在Vue组件中使用:

<template> <button @click="handleOpen">选择文件</button> </template> <script setup> const handleOpen = async () => { const filePath = await window.electronAPI.openDialog() if (filePath) { console.log('选择的文件:', filePath) } } </script>

这种模式是Electron开发中最常用的通信方式。记住几个要点:

  • 预加载脚本使用contextBridge安全地暴露API
  • 主进程用ipcMain.handle处理调用
  • 渲染进程通过window对象访问暴露的API

4. 完善Vue开发环境

4.1 添加Vue全家桶

虽然electron-vite已经配置了Vue3,但我们还需要一些常用工具:

安装路由和状态管理:

npm install vue-router pinia

配置路由(src/renderer/router/index.js):

import { createRouter, createWebHashHistory } from 'vue-router' const routes = [ { path: '/', component: () => import('../views/Home.vue') }, { path: '/about', component: () => import('../views/About.vue') } ] export const router = createRouter({ history: createWebHashHistory(), routes })

配置Pinia(src/renderer/stores/index.js):

import { defineStore } from 'pinia' export const useAppStore = defineStore('app', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } })

在main.js中安装它们:

import { createApp } from 'vue' import App from './App.vue' import { router } from './router' import { createPinia } from 'pinia' const app = createApp(App) app.use(router) app.use(createPinia()) app.mount('#app')

4.2 样式与工具类配置

我习惯使用SCSS和TailwindCSS。先安装必要的依赖:

npm install -D sass tailwindcss postcss autoprefixer npx tailwindcss init

配置tailwind.config.js:

module.exports = { content: [ './src/renderer/**/*.{vue,js,ts,jsx,tsx}' ], theme: { extend: {}, }, plugins: [], }

然后在src/renderer/assets目录下创建main.scss:

@tailwind base; @tailwind components; @tailwind utilities; /* 自定义样式 */

最后在main.js中引入:

import './assets/main.scss'

5. 窗口管理与原生功能

5.1 自定义窗口行为

Electron允许我们完全控制窗口的外观和行为。修改主进程代码创建一个自定义窗口:

const createWindow = () => { const win = new BrowserWindow({ width: 1200, height: 800, minWidth: 800, minHeight: 600, frame: false, // 无边框窗口 titleBarStyle: 'hidden', titleBarOverlay: { color: '#2f3241', symbolColor: '#fff' }, webPreferences: { preload: path.join(__dirname, '../preload/index.js'), webSecurity: false // 开发时允许跨域 } }) if (process.env.VITE_DEV_SERVER_URL) { win.loadURL(process.env.VITE_DEV_SERVER_URL) win.webContents.openDevTools() } else { win.loadFile(path.join(__dirname, '../renderer/index.html')) } }

5.2 实现自定义标题栏

由于我们使用了无边框窗口,需要自己实现标题栏。在Vue组件中:

<template> <div class="titlebar"> <div class="title">我的应用</div> <div class="controls"> <button @click="minimize">-</button> <button @click="maximize">□</button> <button @click="close">×</button> </div> </div> </template> <script setup> const minimize = () => window.electronAPI.minimize() const maximize = () => window.electronAPI.maximize() const close = () => window.electronAPI.close() </script> <style scoped> .titlebar { -webkit-app-region: drag; display: flex; justify-content: space-between; background: #2f3241; color: white; padding: 0 10px; } .controls { -webkit-app-region: no-drag; } .controls button { background: none; border: none; color: white; padding: 0 10px; cursor: pointer; } </style>

对应的预加载脚本API:

contextBridge.exposeInMainWorld('electronAPI', { minimize: () => ipcRenderer.send('window:minimize'), maximize: () => ipcRenderer.send('window:maximize'), close: () => ipcRenderer.send('window:close') })

主进程处理:

ipcMain.on('window:minimize', () => win.minimize()) ipcMain.on('window:maximize', () => { if (win.isMaximized()) { win.unmaximize() } else { win.maximize() } }) ipcMain.on('window:close', () => win.close())

6. 打包与发布

6.1 配置打包选项

electron-vite使用electron-builder进行打包。修改electron-builder.yml:

appId: com.example.myapp productName: 我的应用 copyright: Copyright © 2023 directories: output: dist buildResources: build files: - from: . filter: - "**/*" to: . win: target: - target: nsis arch: - x64 icon: build/icon.ico nsis: oneClick: false perMachine: false allowToChangeInstallationDirectory: true

6.2 处理打包常见问题

国内网络环境下打包可能会遇到下载工具失败的问题。解决方法:

  1. 手动下载所需二进制文件:

    • winCodeSign: https://cdn.npm.taobao.org/dist/electron-builder-binaries/winCodeSign-2.6.0/winCodeSign-2.6.0.7z
    • nsis: https://cdn.npm.taobao.org/dist/electron-builder-binaries/nsis-3.0.4.1/nsis-3.0.4.1.7z
    • nsis-resources: https://cdn.npm.taobao.org/dist/electron-builder-binaries/nsis-resources-3.4.1/nsis-resources-3.4.1.7z
  2. 解压到指定目录:

    • Windows:C:\Users\你的用户名\AppData\Local\electron-builder\Cache

6.3 生成安装包

运行打包命令:

npm run build

打包完成后,dist目录下会有安装包和可执行文件。如果要生成免安装的绿色版,可以配置:

win: target: - target: portable arch: - x64

7. 进阶技巧与优化

7.1 性能优化建议

Electron应用容易变得臃肿,这里有几个优化技巧:

  1. 按需加载Node模块:很多Node模块体积很大,只在主进程需要时再require
  2. 启用上下文隔离:防止渲染进程直接访问Node API,提高安全性
  3. 使用Vite的代码分割:Vue路由的懒加载可以显著减少初始加载时间
  4. 优化渲染进程:像Web应用一样,避免不必要的DOM操作和大型状态

7.2 调试技巧

开发时可以利用这些调试工具:

  • 主进程:VSCode的JavaScript调试终端
  • 渲染进程:Chrome开发者工具(默认会自动打开)
  • 进程通信:在控制台打印ipc通信日志

一个有用的调试配置(.vscode/launch.json):

{ "version": "0.2.0", "configurations": [ { "name": "Debug Main Process", "type": "node", "request": "launch", "cwd": "${workspaceFolder}", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron-vite", "runtimeArgs": ["dev"], "outputCapture": "std", "skipFiles": ["<node_internals>/**"] } ] }

7.3 原生功能扩展

Electron的强大之处在于可以轻松集成原生功能。比如实现一个全局快捷键:

主进程中:

const { globalShortcut } = require('electron') app.whenReady().then(() => { globalShortcut.register('CommandOrControl+Shift+I', () => { win.webContents.openDevTools() }) }) app.on('will-quit', () => { globalShortcut.unregisterAll() })

或者使用系统托盘:

const { Tray, Menu } = require('electron') const path = require('path') let tray = null app.whenReady().then(() => { tray = new Tray(path.join(__dirname, '../resources/tray.png')) const contextMenu = Menu.buildFromTemplate([ { label: '显示', click: () => win.show() }, { label: '退出', click: () => app.quit() } ]) tray.setToolTip('我的应用') tray.setContextMenu(contextMenu) })

8. 项目结构与代码组织

8.1 推荐的项目结构

经过多个Electron项目实践,我总结出这样的目录结构:

src/ ├── main/ │ ├── lib/ # 主进程工具库 │ ├── services/ # 后台服务 │ ├── windows/ # 多窗口管理 │ └── index.js # 主入口 ├── preload/ │ ├── lib/ # 预加载脚本工具 │ └── index.js # 主入口 └── renderer/ ├── src/ │ ├── assets/ │ ├── components/ │ ├── composables/ # Vue组合式函数 │ ├── router/ │ ├── stores/ │ ├── views/ │ ├── App.vue │ └── main.js └── index.html

8.2 状态共享模式

主进程和渲染进程之间共享状态是个常见需求。我通常采用这种模式:

  1. 主进程维护真实状态
  2. 通过ipc暴露状态读写接口
  3. 渲染进程通过Pinia封装这些接口

例如实现一个主题切换功能:

主进程:

let currentTheme = 'light' ipcMain.handle('theme:get', () => currentTheme) ipcMain.handle('theme:set', (_, theme) => { currentTheme = theme win.webContents.send('theme:changed', theme) })

渲染进程的Pinia store:

export const useThemeStore = defineStore('theme', () => { const theme = ref('light') const getTheme = async () => { theme.value = await window.electronAPI.invoke('theme:get') } const setTheme = async (newTheme) => { await window.electronAPI.invoke('theme:set', newTheme) theme.value = newTheme } // 监听主题变化 window.electronAPI.on('theme:changed', (_, newTheme) => { theme.value = newTheme }) return { theme, getTheme, setTheme } })

这种模式保持了单一数据源,同时提供了响应式的使用体验。

http://www.cnnetsun.cn/news/2056657.html

相关文章:

  • 告别龟速 QC:ZeroTier + NAS + Mac 构建极致私有云网
  • 基于深度学习的车辆属性识别 yolo11新能源车牌识别 特种车牌检测 车辆颜色识别与车型识别 汽车品牌logo识别
  • SQL学习-unit7(内置函数)
  • 2026最新|Hermes 接入微信/企业微信/飞书 完整部署教程(亲测可用)
  • 别再乱设DataX的channel和bps了!一份讲透速度控制优先级与优化配置的指南
  • 近似加法器HALOC-AxA设计与图像处理优化
  • JSCJELEC长电长晶原厂原装代理分销经销一级代理分销经销
  • 机器学习中不平衡分类问题的重采样技术解析
  • BOSS直接自动点击未读消息并发送求简历请求
  • GLM-TTS实战案例:用AI语音为你的视频创作增添情感色彩
  • 【VSCode 2026金融安全配置白皮书】:零信任架构下47项关键加固项实测验证(含央行合规对标清单)
  • 别再只会按AutoSet了!手把手教你玩转泰克MSO2000B示波器的触发与采样设置
  • 吊顶里的那根龙骨,后来怎么样了
  • MySQL 同步到目标库后,怎么确认数据一致?NineData 的同步与比对方案
  • 从家庭用电到工业变频:一文搞懂AC-AC变换器的三种核心玩法(相控、斩控、调功)
  • 股市学习心得-股市的一天
  • 顶会论文模块复现与二次创新:顶会 AAAI 2026:Adaptive Frequency Filter(自适应频域滤波)模块在图像去噪中的应用
  • 从‘牛马’到‘老板’:智能体时代的效率革命
  • 基于YOLO26的Apex游戏人物目标检测系统设计与实现(项目源码+数据集+模型权重+UI界面+python+深度学习+远程环境部署)
  • 遇水易释氢燃爆,镁合金加工润滑痛点一次性讲透
  • Ubuntu 20.04下,用Anaconda虚拟环境搞定pycairo和PyGObject安装(附清华源加速)
  • 【2026内存安全编码白皮书】:C语言开发者必看的5大零成本迁移路径与3类高危误用规避指南
  • CST案例:利用电流钳(current probe)测试实现电源模块的CE仿真
  • entity dto vo
  • 告别双系统!Win11下用WSL2+Ubuntu 20.04打造无缝AI开发环境(附Anaconda/PyTorch配置)
  • Udio 音频生成 API 集成指南
  • 智慧教育中的个性化学习与教学评估
  • 混合块注意力机制(MoBA)原理与实现详解
  • 国产化即时通讯软件怎么选?BeeWorks 的“全栈信创”答卷
  • 美的智能家电云端依赖的终结:Home Assistant本地网络控制方案