4、前端框架集成:在Electron中集成React/Vue;使用Vite作为构建工具;配置热更新(HMR);解决跨域与资源加载问题
好,咱们进入第四章节。说实话,这一章是很多初学者觉得「头大」的地方。为什么?因为Electron本身是个壳,真正干活的是前端框架。怎么把React或Vue塞进去,怎么让开发体验像写Web应用一样爽,怎么处理那些烦人的跨域问题——嗯,今天咱们一次性说清楚。
4.1 为什么选Vite?
我个人习惯用Vite作为构建工具。原因很简单:快。真的快。
以前用Webpack,改一行代码等两三秒刷新,那种感觉就像在等老电脑开机。Vite基于ES Module,开发时按需编译,冷启动几乎秒开。我在项目中遇到过一个大项目,Webpack启动要40秒,换成Vite后直接降到2秒。你想想看,这体验差距有多大。
当然,Vite对Electron的支持也很成熟。社区有现成的插件,比如electron-vite,或者直接用vite-plugin-electron。我个人更推荐后者,配置灵活,而且不侵入原有Vite配置。
4.2 集成React
先说说React。如果你用Vite创建React项目,默认模板就带HMR。但集成到Electron里,有几个关键点要注意。
首先,安装依赖:
npm create vite@latest my-electron-app -- --template react
cd my-electron-app
npm install electron vite-plugin-electron electron-builder --save-dev
然后,在vite.config.js里配置插件:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import electron from 'vite-plugin-electron'
export default defineConfig({
plugins: [
react(),
electron([
{
entry: 'electron/main.js',
},
{
entry: 'electron/preload.js',
onstart(args) {
args.reload()
},
},
]),
],
})
这里有个坑。我曾经在配置onstart时忘了写args.reload(),结果每次改主进程代码都要手动重启。嗯,这个小细节浪费了我半小时。
React组件里的热更新是自动的。你改个JSX,页面瞬间刷新。但要注意,如果改了主进程代码,Electron窗口会整个重启,这是正常的。
4.3 集成Vue
Vue的集成思路和React差不多。Vite官方对Vue的支持更好,毕竟都是尤大出品。
创建项目:
npm create vite@latest my-vue-electron -- --template vue
cd my-vue-electron
npm install electron vite-plugin-electron electron-builder --save-dev
配置vite.config.js:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import electron from 'vite-plugin-electron'
export default defineConfig({
plugins: [
vue(),
electron([
{
entry: 'electron/main.js',
},
]),
],
})
Vue的HMR体验比React更丝滑。因为Vue的模板编译是运行时进行的,改模板几乎无感知。我在做一个后台管理系统时,Vue的HMR从来没让我失望过。React偶尔会因为状态丢失需要手动刷新,Vue基本不用操心。
4.4 配置热更新(HMR)
HMR说白了就是「改代码不刷新页面,只替换改动的模块」。这玩意儿在Electron里稍微有点特殊。
为什么?因为Electron有两个进程:主进程和渲染进程。渲染进程的HMR和Web开发一样,但主进程的HMR需要特殊处理。
我建议的做法是:
- 渲染进程:直接用Vite自带的HMR,不用额外配置
- 主进程:用
vite-plugin-electron的onstart回调,检测到变化后重启Electron - 预加载脚本:同样用
onstart,但调用args.reload()只刷新窗口
这里有个小技巧。如果你觉得每次改主进程都重启窗口太慢,可以试试electron-reloader这个包。它能在不重启窗口的情况下热更新主进程代码。不过说实话,稳定性一般,我试过几次后还是回到了重启方案。
4.5 解决跨域与资源加载问题
跨域问题,是Electron开发里最容易被忽视的坑。你想想看,Electron的渲染进程加载的是file://协议,而你的API请求是http://协议。浏览器会直接拦截。
解决方案有三种:
| 方案 | 适用场景 | 优缺点 |
|---|---|---|
设置webSecurity: false |
开发环境快速调试 | 简单但不安全,生产环境不能用 |
使用contextBridge + 主进程代理 |
生产环境推荐 | 安全,但需要额外写代理代码 |
| 配置CORS头(后端配合) | 后端可控制时 | 最规范,但需要后端改代码 |
我个人最常用的是第二种。在预加载脚本里暴露一个API,主进程用net模块发请求,这样既安全又灵活。
举个例子:
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('api', {
fetch: (url, options) => ipcRenderer.invoke('fetch', url, options)
})
// main.js
const { ipcMain, net } = require('electron')
ipcMain.handle('fetch', async (event, url, options) => {
const response = await net.fetch(url, options)
return response.json()
})
这样渲染进程里直接调用window.api.fetch('/api/data'),完全不会有跨域问题。
webSecurity。我曾经见过一个项目,开发时图省事关了,上线后被人用XSS攻击,用户数据泄露。这个教训很深刻。
4.6 资源加载问题
资源加载,说白了就是图片、字体、静态文件怎么在Electron里正确显示。
在Web开发里,你写<img src="/logo.png">,浏览器会自动从服务器根目录加载。但在Electron里,/指向的是file://协议的根目录,也就是你的应用安装目录。这会导致路径错乱。
我的做法是:
- 开发时:把静态资源放在
public文件夹,Vite会自动处理路径 - 生产时:用
__dirname或app.getAppPath()拼接绝对路径 - 最佳实践:所有资源都通过Vite的
import引入,让构建工具处理路径
举个例子:
// 不推荐
const img = new Image()
img.src = 'assets/logo.png' // 路径容易出错
// 推荐
import logo from './assets/logo.png'
const img = new Image()
img.src = logo // Vite会处理成正确路径
嗯,这里要注意。如果你用了file://协议加载本地文件,记得在BrowserWindow的webPreferences里设置webSecurity: false(仅开发环境)。或者更安全的方式,用protocol.registerFileProtocol注册自定义协议。
核心总结:
- Vite是Electron开发的最佳拍档,快就一个字
- React和Vue的集成方式几乎一样,选你喜欢的就行
- HMR默认支持渲染进程,主进程需要额外配置
- 跨域问题用主进程代理解决,别偷懒关安全设置
- 资源加载用Vite的import机制,别手动拼路径
好了,这一章的内容就这些。下一章咱们聊聊打包和分发,那才是真正让应用「落地」的关键一步。到时候见。