Electron 与前端框架 (React, Vue, Angular) 集成教程
Electron 可以与现代前端框架无缝集成,结合各自的优势开发功能丰富的桌面应用。以下是详细的集成指南。
目录
- Electron 与 React 集成
- Electron 与 Vue 集成
- Electron 与 Angular 集成
- 通用集成技巧
- 常见问题解决
Electron 与 React 集成
方法一:手动集成(推荐)
- 创建 React 项目并安装 Electron:
npx create-react-app my-electron-react-app
cd my-electron-react-app
npm install electron electron-builder --save-dev
- 添加 Electron 主进程文件
public/electron.js
:
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
})
// 开发环境加载开发服务器,生产环境加载构建文件
if (process.env.NODE_ENV === 'development') {
win.loadURL('http://localhost:3000')
win.webContents.openDevTools()
} else {
win.loadFile(path.join(__dirname, '../build/index.html'))
}
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
- 创建预加载脚本
public/preload.js
:
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
send: (channel, data) => ipcRenderer.send(channel, data),
on: (channel, func) => ipcRenderer.on(channel, (event, ...args) => func(...args))
})
- 修改
package.json
:
{
"main": "public/electron.js",
"homepage": "./",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron": "electron .",
"electron-dev": "concurrently \"npm run start\" \"wait-on http://localhost:3000 && npm run electron\"",
"pack": "electron-builder --dir",
"dist": "npm run build && electron-builder"
},
"build": {
"appId": "com.example.electronreact",
"files": [
"build/**/*",
"node_modules/**/*",
"public/electron.js",
"public/preload.js"
],
"directories": {
"buildResources": "assets"
}
}
}
- 安装额外依赖:
npm install concurrently wait-on --save-dev
- 启动开发环境:
npm run electron-dev
- 构建生产版本:
npm run dist
方法二:使用现成模板
git clone https://github.com/electron-react-boilerplate/electron-react-boilerplate.git
cd electron-react-boilerplate
npm install
npm start
Electron 与 Vue 集成
方法一:手动集成
- 创建 Vue 项目并安装 Electron:
npm init vue@latest my-electron-vue-app
cd my-electron-vue-app
npm install
npm install electron electron-builder --save-dev
- 添加 Electron 主进程文件
electron/main.js
:
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
})
if (process.env.NODE_ENV === 'development') {
win.loadURL('http://localhost:5173')
win.webContents.openDevTools()
} else {
win.loadFile(path.join(__dirname, '../dist/index.html'))
}
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
- 创建预加载脚本
electron/preload.js
:
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
send: (channel, data) => ipcRenderer.send(channel, data),
on: (channel, func) => ipcRenderer.on(channel, (event, ...args) => func(...args))
})
- 修改
package.json
:
{
"main": "electron/main.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"electron": "electron .",
"electron-dev": "concurrently \"npm run dev\" \"wait-on http://localhost:5173 && npm run electron\"",
"pack": "electron-builder --dir",
"dist": "npm run build && electron-builder"
},
"build": {
"appId": "com.example.electronvue",
"files": [
"dist/**/*",
"electron/**/*",
"node_modules/**/*"
]
}
}
- 修改
vite.config.js
确保资源路径正确:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
base: './'
})
- 启动开发环境:
npm run electron-dev
- 构建生产版本:
npm run dist
方法二:使用 Vue CLI Plugin
vue create my-electron-vue-app
cd my-electron-vue-app
vue add electron-builder
npm run electron:serve
npm run electron:build
Electron 与 Angular 集成
方法一:手动集成
- 创建 Angular 项目并安装 Electron:
ng new my-electron-angular-app
cd my-electron-angular-app
npm install electron electron-builder --save-dev
- 添加 Electron 主进程文件
electron/main.js
:
const { app, BrowserWindow } = require('electron')
const path = require('path')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
})
if (process.env.NODE_ENV === 'development') {
win.loadURL('http://localhost:4200')
win.webContents.openDevTools()
} else {
win.loadFile(path.join(__dirname, '../dist/my-electron-angular-app/index.html'))
}
}
app.whenReady().then(createWindow)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
- 创建预加载脚本
electron/preload.js
:
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
send: (channel, data) => ipcRenderer.send(channel, data),
on: (channel, func) => ipcRenderer.on(channel, (event, ...args) => func(...args))
})
- 修改
package.json
:
{
"main": "electron/main.js",
"scripts": {
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"electron": "electron .",
"electron-dev": "concurrently \"npm run start\" \"wait-on http://localhost:4200 && npm run electron\"",
"pack": "electron-builder --dir",
"dist": "npm run build && electron-builder"
},
"build": {
"appId": "com.example.electronangular",
"files": [
"dist/**/*",
"electron/**/*",
"node_modules/**/*"
]
}
}
- 修改
angular.json
确保资源路径正确:
{
"projects": {
"your-project-name": {
"architect": {
"build": {
"options": {
"baseHref": "./",
"outputPath": "dist"
}
}
}
}
}
}
- 启动开发环境:
npm run electron-dev
- 构建生产版本:
npm run dist
方法二:使用 ngx-electron
- 安装 ngx-electron:
ng add ngx-electron
- 在组件中使用:
import { ElectronService } from 'ngx-electron'
@Component({...})
export class MyComponent {
constructor(private _electronService: ElectronService) {}
sendMessage() {
this._electronService.ipcRenderer.send('message', 'Hello')
}
}
通用集成技巧
1. 开发环境与生产环境区分
// 在主进程中
const isDev = process.env.NODE_ENV === 'development'
// 在渲染进程中
const isDev = process.env.NODE_ENV === 'development' ||
(window.process && window.process.env && window.process.env.NODE_ENV === 'development')
2. 共享代码
在 package.json
中配置别名:
{
"exports": {
"./shared": "./src/shared/index.js"
}
}
3. 热重载
安装 electron-reloader:
npm install electron-reloader --save-dev
在主进程中使用:
try {
require('electron-reloader')(module)
} catch (_) {}
4. 跨框架组件通信
使用自定义事件:
// 发送事件
window.dispatchEvent(new CustomEvent('electron-event', { detail: data }))
// 接收事件
window.addEventListener('electron-event', (event) => {
console.log(event.detail)
})
5. 状态管理集成
以 Redux 为例:
// 预加载脚本中暴露 store
contextBridge.exposeInMainWorld('electronStore', {
getState: () => ipcRenderer.invoke('store-get-state'),
dispatch: (action) => ipcRenderer.send('store-dispatch', action),
subscribe: (callback) => {
ipcRenderer.on('store-state-changed', (event, state) => callback(state))
}
})
常见问题解决
1. 白屏问题
- 确保正确加载了 HTML 文件
- 检查开发者工具中的错误
- 确认资源路径正确(特别是生产环境)
2. require is not defined
- 确保
nodeIntegration: false
和contextIsolation: true
- 使用预加载脚本暴露必要 API
3. 样式不加载
- 确保 CSS 文件路径正确
- 检查 CSP 设置
- 使用绝对路径或 base href
4. 打包后功能异常
- 确保所有依赖包含在打包文件中
- 检查文件路径是否正确
- 测试生产构建而非开发环境
5. 原生模块问题
- 使用
electron-rebuild
重新编译 - 检查模块是否兼容 Electron 版本
- 考虑替代方案或自己实现功能
总结
Electron 与前端框架集成可以充分发挥各自优势:
- React:组件化开发 + 强大状态管理
- Vue:简洁语法 + 响应式系统
- Angular:完整框架 + 依赖注入
关键集成点:
- 正确配置主进程和渲染进程
- 安全地实现进程间通信
- 处理好开发和生产环境的差异
- 优化打包配置
选择适合你项目的集成方式,遵循安全最佳实践,就能构建出功能强大、用户体验良好的跨平台桌面应用。