Electron 与前端框架
本教程共 45 篇 · 第 41 篇 · 更新于 2026-08-03
41. Electron 与前端框架
本节目标
- 理解 Electron 与前端框架的分工边界。
- 了解 electron-vite 等主流集成模板。
- 掌握常见的项目目录约定。
- 知道 preload 如何与框架代码共存。
- 避开把框架塞进渲染进程的常见误区。
1-1 为什么能直接用前端框架
Electron 的渲染进程本质上就是一个 Chromium 浏览器环境。只要你的界面是 HTML、CSS 和 JavaScript,就能用 Web 生态里几乎所有框架来写——React、Vue、Angular、Svelte 都不例外。它们的组件、状态管理、路由,在渲染进程里和你写网页时完全一样。
关键在于:框架只负责「界面与交互」,需要触碰操作系统能力(读写文件、弹系统通知、操作托盘)时,仍要走主进程,并通过 preload 暴露的桥接 API 来调用。换句话说,框架住在渲染进程,Electron 的原生能力住在主进程,二者通过 IPC 沟通。
这里有一个硬约束要牢记:渲染进程默认没有 Node 能力,所以你不能在 React 组件里直接 require('fs')。要么用主进程做文件操作再通过 IPC 回传,要么用打包器把需要的 npm 库打包进渲染进程(就像在网页里用 webpack、Vite 那样)。
1-2 主流集成模板与工具
Electron 官方对「怎么写、怎么打包」保持开放态度,并不限定必须用某个框架。但社区里已经沉淀出成熟方案,新手直接套用能省去大量搭建成本。
Electron Forge 是官方主推的打包与发布工具,它自带基于 Webpack 的模板。对于前端框架,社区更流行的是 electron-vite(基于 Vite 的构建方案),它对 React、Vue、Angular 都有开箱模板,开发体验接近纯前端项目。
# 使用 electron-vite 创建一个 React 模板(社区方案)
npm create @quick-start/electron@latest my-app -- --template react-ts
# 或者使用 Electron Forge 官方模板(webpack 方案)
npm create electron-app@latest my-app
提示:本书打包主线以 Electron Forge 为准。electron-vite、electron-react-boilerplate 等属于社区模板,作为「对比与可选方案」了解即可,它们只是帮你更快地搭好脚手架,并不改变 Electron 的进程模型与 IPC 范式。
选型时可以这样取舍:如果你希望官方背书、打包发布一条龙、少操心底层配置,选 Electron Forge;如果你更在意 Vite 带来的极速热更新、以及和纯前端项目一致的工程体验,electron-vite 更顺手。两者的差异主要在构建链与脚手架,渲染进程里写 React/Vue 的方式完全一样,preload 与主进程的写法也完全一致。新手不必在「哪个模板更好」上纠结太久——任选一个把应用跑起来,比空谈方案更有价值。真正决定代码质量的,是你能不能守住安全默认,而不是用了哪套工具。
1-3 推荐的目录约定
无论用哪个框架,一个清晰的目录约定能避免主进程、渲染进程、preload 三者互相污染。下面是一个 electron-vite 风格的常见结构:
my-app/
├── electron/
│ ├── main.ts # 主进程入口
│ └── preload.ts # 预加载脚本
├── src/
│ ├── main.tsx # 框架(React/Vue)渲染入口
│ ├── App.tsx # 根组件
│ └── components/ # 业务组件
├── package.json
└── vite.config.ts
要点是:Electron 相关代码放在 electron/ 下,与框架源码 src/ 物理分离;主进程只打包成 Node 环境可运行的脚本,渲染进程则由 Vite 编译成静态资源再被 BrowserWindow 加载。
主进程入口的标准写法不会因框架而改变:
// 主进程 electron/main.ts
const { app, BrowserWindow } = require('electron')
const path = require('node:path')
function createWindow () {
const win = new BrowserWindow({
width: 1000,
height: 700,
webPreferences: {
// 沙箱 + 隔离是框架集成时的安全底线
sandbox: true,
contextIsolation: true,
nodeIntegration: false,
preload: path.join(__dirname, '../preload.js')
}
})
// 开发环境加载 Vite 本地服务,生产环境加载打包后的文件
if (process.env.VITE_DEV_SERVER_URL) {
win.loadURL(process.env.VITE_DEV_SERVER_URL)
} else {
win.loadFile(path.join(__dirname, '../dist/index.html'))
}
}
app.whenReady().then(createWindow)
1-4 preload 与框架共存
preload 与框架完全可以共存,而且这正是官方推荐的模式:preload 用 contextBridge 把受控 API 挂到 window 上,框架代码在渲染进程里通过 window.electronAPI 调用,二者互不干扰。
// 预加载脚本 preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
// 只暴露业务需要的最小接口
getVersion: () => ipcRenderer.invoke('get-app-version'),
onUpdate: (callback) => ipcRenderer.on('app-update', (_e, v) => callback(v))
})
// 渲染进程(React)src/App.tsx
import { useEffect, useState } from 'react'
export default function App () {
const [version, setVersion] = useState('')
useEffect(() => {
window.electronAPI.getVersion().then(setVersion)
}, [])
return <h1>当前版本:{version}</h1>
}
提示:不要因为用了框架就在渲染进程里打开
nodeIntegration。框架组件仍需通过window.electronAPI走 IPC。直接把ipcRenderer原样暴露给页面也属于不安全做法,应当像上面一样只暴露包装后的函数。
1-5 框架视角的几个注意点
第一,路由问题。单页应用(SPA)的路由通常用 history 模式,但打包后加载本地文件时,history 路由在刷新时会找不到路径。生产环境建议用 hash 路由,或配合自定义协议与本地服务器加载,避免刷新 404。
第二,进程隔离思维。永远记住界面代码跑在渲染进程,凡是涉及文件、系统通知、托盘、自动更新等,都要回到主进程处理。把「谁的活儿」分清楚,架构才不会乱。
第三,性能。框架体积本身会带来启动开销,建议开启按需加载、代码分割,并参考性能章节的优化手段,别让首屏被一个巨大的 bundle 拖慢。
1-6 开发态与生产态的加载差异
开发时,框架通常由 Vite 或 Webpack 的本地服务托管,渲染进程加载的是 http://localhost:3000 这样的地址;生产时则加载你打包出来的 dist/index.html 静态文件。这个切换最好在 BrowserWindow 的创建逻辑里用一个环境变量(如 VITE_DEV_SERVER_URL)来区分,而不是写死两套代码。注意开发态下页面跑在 localhost,不受 file:// 的权限问题困扰,但一旦打包,所有资源都要走本地文件或自定义协议。
调试方面,渲染进程可以直接用 Chromium 自带的 DevTools(按 F12 或在主进程调用 win.webContents.openDevTools());框架的 React DevTools、Vue DevTools 也能照常安装使用。主进程调试则需要在启动命令后加 --inspect,再用 VS Code 或 Chrome 的 chrome://inspect 连接。两者是独立的调试会话,不要混淆。掌握这套「开发态热更新、生产态静态加载」的节奏,你就能把熟悉的前端工作流无缝搬进 Electron。
小结
Electron 与前端框架是「各司其职」的关系:框架负责界面,Electron 负责原生能力,preload + IPC 是它们之间的安全纽带。选 electron-vite 这类模板能快速起步,但无论模板怎么变,contextIsolation、nodeIntegration: false、sandbox 这些红线不变。下一章我们看主进程能调用哪些 Node.js 能力。