Electron + Vite + Vue 项目中的 IPC 通信三层封装实践
electron-vite-vue 是一个由社区维护的轻量级脚手架项目,集成了:
它帮助开发者快速搭建出具有前后端隔离、热更新、预加载脚本支持的 Electron 桌面应用开发环境,适合个人工具、跨平台客户端、管理后台等场景。
在这个基础上,我们希望进一步规范主进程与渲染进程之间的通信逻辑,封装一套结构清晰的 IPC 模块,以便项目功能增长时也能保持良好的可维护性。
本文将介绍如何实现这一目标,包括:
- 主进程逻辑统一注册
- Preload 中安全暴露 API
- 渲染进程中统一调用
📦 项目结构示意
electron-vite-vue/
├── electron/
│ ├── main/
│ │ └── ipcHandlers.ts ← 主进程统一注册 IPC
│ └── preload/
│ └── index.ts ← contextBridge 暴露 API
├── src/
│ ├── App.vue
│ ├── main.ts
│ └── types/
│ └── electron-api.d.ts ← 类型提示(可选)
🧠 目标通信结构
渲染进程 → Preload 暴露 API → 主进程处理逻辑 → 返回数据或执行动作
🧱 1. 主进程封装:ipcHandlers.ts
ts
// electron/main/ipcHandlers.ts
import { app, ipcMain, BrowserWindow, dialog, shell } from 'electron'
export function setupIpcHandlers(win: BrowserWindow) {
ipcMain.handle('get-app-version', () => {
return app.getVersion()
})
ipcMain.handle('select-file', async () => {
return await dialog.showOpenDialog({ properties: ['openFile'] })
})
ipcMain.on('window-minimize', () => win.minimize())
ipcMain.on('open-external', (_, url) => {
shell.openExternal(url)
})
}
然后在主进程入口(如 electron/main/index.ts
)注册:
ts
import { setupIpcHandlers } from './ipcHandlers'
// 创建窗口后调用
setupIpcHandlers(win)
🛡️ 2. Preload 层暴露:preload/index.ts
ts
// electron/preload/index.ts
import { contextBridge, ipcRenderer } from 'electron'
contextBridge.exposeInMainWorld('electronAPI', {
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
selectFile: () => ipcRenderer.invoke('select-file'),
minimizeWindow: () => ipcRenderer.send('window-minimize'),
openExternal: (url: string) => ipcRenderer.send('open-external', url),
onNavigate: (callback: (path: string) => void) => {
ipcRenderer.on('navigate-to', (_, path) => callback(path))
}
})
💻 3. 渲染进程使用示例:App.vue
ts
<script setup lang="ts">
const checkVersion = async () => {
const version = await window.electronAPI.getAppVersion()
console.log('当前版本:', version)
}
const selectAndLogFile = async () => {
const result = await window.electronAPI.selectFile()
if (!result.canceled && result.filePaths.length > 0) {
console.log('文件路径:', result.filePaths[0])
}
}
const openGitHub = () => {
window.electronAPI.openExternal('https://github.com/electron-vite/electron-vite-vue')
}
</script>
<template>
<button @click="checkVersion">获取版本</button>
<button @click="selectAndLogFile">选择文件</button>
<button @click="openGitHub">打开 GitHub</button>
</template>
💡 4. 类型提示增强(可选):electron-api.d.ts
ts
// src/types/electron-api.d.ts
export interface ElectronAPI {
getAppVersion(): Promise<string>
selectFile(): Promise<{ canceled: boolean, filePaths: string[] }>
minimizeWindow(): void
openExternal(url: string): void
onNavigate(cb: (path: string) => void): void
}
declare global {
interface Window {
electronAPI: ElectronAPI
}
}
并在 tsconfig.json
中添加类型目录:
json
{
"compilerOptions": {
"types": ["vite/client", "./src/types/electron-api"]
}
}
🧪 5. 测试建议
- 确保
preload
在vite.config.ts
中配置正确 - 确保你使用
contextIsolation: true
、nodeIntegration: false
- 主进程与渲染进程中 API 名称一致,避免大小写错误
✅ 总结
通过上述结构,我们实现了:
- IPC 注册集中管理,主进程清晰职责分离
- 渲染进程只需
window.electronAPI.xxx()
调用 - 满足 Electron 安全通信规范(基于
contextBridge
)
这为后续功能扩展打下了良好基础,适用于中大型 Electron 桌面应用项目。
如需示例代码,可参考项目模板:electron-vite-vue
欢迎点赞、收藏、分享 🙌