人人都会AI编程

8.3 前端框架整合

更新时间:2026-07-11

Electron 的渲染进程本质上就是一个可以运行任意前端框架的浏览器环境。从技术上讲,你完全可以直接在 index.html 里用 CDN 引入 Vue 或 React 的 UMD 文件开始写界面,但在实际项目中,这么做很快会遭遇组件化开发、热更新、状态管理、路由等工程化的需求。这一节会告诉你如何将主流前端框架“真正”地整合进 Electron 项目,并且是生产可用的方式。

8.3.1 整合的基本思路

无论你使用哪种框架,整合的核心目标都是让开发体验和普通的 Web 单页应用一样,同时保证 Electron 的安全模型不被破坏。最典型的架构模式如下:

  • 用一个前端构建工具(Vite、Webpack 等)单独管理全部渲染进程代码。
  • 开发时,构建工具启动一个 dev server(如 localhost:5173),Electron 窗口加载这个地址,享受模块热替换(HMR)和极快的刷新速度。
  • 生产构建时,先将前端代码打包成静态文件(dist/index.html + JS/CSS),再由 Electron 的 win.loadFile 加载本地文件。
  • 主进程代码单独编写,不需要被前端构建工具处理(或用 electron-vite 等工具一同管理)。

这种“前后端分离”的架构,跟 Electron 主进程 / 渲染进程的划分天然契合。

8.3.2 使用脚手架快速起步

手动配置 Webpack 和 Babel 太过繁琐,社区提供了若干成熟的脚手架来降低门槛:

  • electron-vite(推荐)

基于 Vite,一体式管理主进程、预加载脚本和渲染进程。它直接支持 Vue、React、Svelte 等模板,开箱即用地解决了 HMR、路径别名、环境变量注入等问题。

  • electron-forge + Vite 模板

Electron 官方维护的 forge 工具也提供了基于 Vite 的模板,选择时添加 --template=vite 参数即可,之后同样可以集成 Vue 或 React。

  • electron-react-boilerplateelectron-vue-template

针对特定框架的社区模板,历史较长,但部分可能依赖老旧工具链(如 Babel),选择时注意看维护状态。

如果是从零开始的真实项目,我比较推荐 electron-vite。它的目录结构极其清晰:

my-app/
├── electron.vite.config.js
├── src/
│   ├── main/          # 主进程代码
│   ├── preload/       # 预加载脚本
│   └── renderer/      # 渲染进程(Vue/React 项目)
│       ├── index.html
│       └── src/
└── package.json

你只需要在初始化时选择框架,就能直接开始写业务代码。

8.3.3 手工集成 Vue 3 的例子

假设你想在现有 Electron 项目里手工加上 Vue 3 + Vite,可以按以下步骤操作(同样适用于 React,仅构建细节不同)。

1. 安装依赖

npm install vue
npm install -D vite @vitejs/plugin-vue

2. 创建 Vite 配置(项目根目录下 vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  root: 'src/renderer',   // 渲染进程源码目录
  base: './',             // 确保资源路径使用相对路径
  build: {
    outDir: '../../dist/renderer',
    emptyOutDir: true,
  },
  server: {
    port: 5173,
  },
})

3. 在 src/renderer 里搭建 Vue 应用

src/renderer/
├── index.html
├── src/
│   ├── main.js
│   └── App.vue

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>My App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./src/main.js"></script>
  </body>
</html>

src/main.js

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

src/App.vue

<template>
  <div>
    <h1>Hello from Vue 3!</h1>
    <button @click="sendMsg">Send to Main</button>
  </div>
</template>

<script setup>
import { ipcRenderer } from 'electron' // 注意安全,如是预加载则从 contextBridge 暴露的 api 调用

function sendMsg() {
  // 此处仅供示例,真实代码应在 preload 中安全暴露
  window.api?.send('toMain', 'Hello')
}
</script>

4. 在主进程中根据环境加载不同内容

// main.js 主进程
const win = new BrowserWindow({
  // ...
  webPreferences: {
    preload: path.join(__dirname, 'preload.js'),
  },
})

if (process.env.VITE_DEV_SERVER_URL) {
  // 开发模式,加载 Vite 服务器
  win.loadURL(process.env.VITE_DEV_SERVER_URL)
} else {
  // 生产模式,加载打包后的文件
  win.loadFile(path.join(__dirname, '../dist/renderer/index.html'))
}

VITE_DEV_SERVER_URL 这个环境变量可以由 electron-vite 自动注入,如果是手工配置,可以在开发脚本里用 cross-env 设置,或者自己写一小段判断代码去找 Vite 的端口。

8.3.4 必须注意的安全实践

整合前端框架时最容易被忽视的就是安全。由于渲染进程天然可以运行任意 JavaScript,你绝对不能图一时方便而启用 nodeIntegration: true 并把 contextIsolation 关掉。

现代 Electron 的安全底线是:

  • contextIsolation: true(默认)
  • nodeIntegration: false(默认)
  • 通过 preload 脚本 + contextBridge 精确暴露给渲染进程有限的 API。

也就是说,你的 Vue/React 组件中不应该能直接 require('fs')require('electron')。如果需要从渲染进程调用主进程能力,应该这样做:

// preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('api', {
  openFile: () => ipcRenderer.invoke('dialog:openFile'),
  // ... 其他白名单方法
})

然后在组件里调用 window.api.openFile()。这种封装方式不仅安全,还能让你直观地看见应用暴露了哪些系统能力,方便审计和测试。

8.3.5 开发时的热更新与调试

将前端框架的运行环境完全交给了 Vite 后,所有的 HMR、快速刷新、错误遮罩层都是即开即用。你只需在启动脚本中先启动 Vite dev server,然后再起 Electron:

"scripts": {
  "dev": "concurrently \"vite\" \"wait-on http://localhost:5173 && electron .\""
}

这样修改 Vue/React 组件时,Electron 窗口会立刻反映变化,和浏览器开发别无二致。此外,你依然可以在 Electron 窗口内使用 DevTools(Ctrl+Shift+I),并安装 Vue DevTools 或 React DevTools 的浏览器扩展,调试组件树和状态。

// 仅在开发模式时自动打开 DevTools
if (process.env.NODE_ENV === 'development') {
  win.webContents.openDevTools()
}

8.3.6 路由与多窗口

使用前端路由(vue-router、react-router)时,注意 Electron 加载的是一个本地文件,默认的 history 模式会依赖服务器配置,所以最稳妥的方式是使用 hash 模式

// vue-router
import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [...]
})

如果你需要在应用中创建多个窗口(比如设置页、浮动工具窗口),每个窗口都应该拥有自己独立的渲染进程和 HTML 入口。你可以在主进程中为不同入口准备不同的 BrowserWindow,并分别加载二次打包后的页面。通常的实践是:主窗口加载 renderer/index.html,设置窗口加载 renderer/settings.html,并且都由同一套 Vite 构建输出两个 HTML 文件。

// vite.config.js 多入口
build: {
  rollupOptions: {
    input: {
      main: resolve(__dirname, 'src/renderer/index.html'),
      settings: resolve(__dirname, 'src/renderer/settings/index.html'),
    }
  }
}

这样 Electron 的应用能力就与前端框架的工程化结构无缝结合了。

8.3.7 真实项目的目录结构推荐

结合前面所有内容,一个生产级 Electron 项目整合前端框架后的目录可能是这样的:

my-electron-app/
├── package.json
├── electron.vite.config.js
├── src/
│   ├── main/                 # 主进程
│   │   ├── index.js          # 入口,创建窗口等
│   │   └── ipc-handlers.js   # IPC 通信逻辑
│   ├── preload/              # 预加载脚本
│   │   └── index.js
│   └── renderer/             # Vue 或 React 前端项目
│       ├── index.html
│       ├── settings.html
│       └── src/
│           ├── main.js
│           ├── App.vue
│           ├── router/
│           ├── stores/
│           └── components/
├── resources/                # 图标等静态资源
└── build/                    # 打包配置 (electron-builder)

这个结构清晰划分了三个主要部分,任何新同事都能快速看懂并上手修改。


前端框架与 Electron 的整合绝非简单地塞入一个 <script> 标签。它需要你正确搭建构建工具链、坚守安全隔离原则,并为多窗口、路由等桌面特有需求做出适配。一旦完成这一步,你的 Electron 应用就真正拥有了 Web 世界里最先进的开发体验,等于用与纯前端项目几乎相同的代码结构和迭代速度,来交付一个带有完整系统权限的桌面程序。这,正是 Electron 赋予开发者的最强大生产力之一。