关于 desktop-framework-electron
面向 Electron 桌面应用开发的技能指南,涵盖主进程与渲染进程架构、安全 IPC、原生系统 API 及打包更新实践。
主要功能
- 01主进程与渲染进程架构
- 02安全 BrowserWindow 配置
- 03通过 contextBridge 封装 IPC
- 04请求响应与消息推送模式
- 05原生系统 API 与深度链接
- 06应用打包及自动更新
适用场景
- 01搭建跨平台 Electron 桌面应用
- 02设计并验证进程间通信
- 03集成菜单、托盘和文件对话框
- 04配置分发及应用自动更新
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agents-inc/ skills --skill desktop-framework-electron安装后在 Claude Code 中输入/desktop-framework-electron确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
metadata.yamlreference.mdexamples/core.mdipc.mdnative-apis.mdpackaging.mdsecurity.md详细介绍
Electron 桌面应用
快速指南: Electron 应用运行两种进程:主进程(Node.js,管理窗口和系统 API)和渲染进程(Chromium,每个窗口一个)。它们之间的所有通信都通过 IPC 进行,并由预加载脚本使用
contextBridge暴露精简、类型明确的 API。切勿禁用contextIsolation。切勿在渲染进程中启用nodeIntegration。使用 Electron Forge 或 Electron Builder 打包。通过autoUpdater(macOS/Windows 上使用 Squirrel)或适用于所有平台的electron-updater自动更新。
<critical_requirements>
重要:使用此技能前
(必须保持 contextIsolation: true(默认设置)——禁用它会将整个预加载作用域暴露给不可信的渲染进程代码)
(必须在预加载脚本中使用 contextBridge.exposeInMainWorld()——切勿直接暴露 ipcRenderer)
(不得在任何 BrowserWindow 中启用 nodeIntegration: true——这会让渲染进程获得完整的 Node.js 访问权限,造成严重安全漏洞)
(必须在主进程中验证并清理通过 IPC 接收的所有数据——将渲染进程消息视为不可信输入)
(必须使用 ipcMain.handle() / ipcRenderer.invoke() 实现请求-响应式 IPC——避免使用会阻塞渲染进程的 sendSync)
(不得在启用 nodeIntegration 或禁用 contextIsolation 的情况下加载远程 URL——这相当于向远程站点授予完整的系统访问权限)
</critical_requirements>
自动检测: Electron、electron、BrowserWindow、ipcMain、ipcRenderer、contextBridge、preload、webPreferences、electron-builder、electron-forge、app.whenReady、electronAPI、mainWindow、autoUpdater、nativeTheme、safeStorage、Tray、Menu、dialog、protocol、shell
适用场景:
- 构建跨平台桌面应用
- 配置主进程 / 渲染进程架构
- 设置安全的 IPC 通信模式
- 集成原生操作系统功能(托盘、菜单、对话框、通知、文件系统)
- 打包和分发桌面应用
- 实现自动更新功能
- 注册自定义协议处理程序 / 深层链接
不适用场景:
- 为渲染进程选择 UI 框架(使用相应的 Web 框架技能)
- 为渲染进程 UI 设置样式(使用相应的样式技能)
- 与主进程无关的服务端或后端逻辑
- 移动应用(Electron 仅适用于桌面)
- 无需 GUI 的 CLI 工具
关键模式
模式 1:安全创建 BrowserWindow
每个 BrowserWindow 都必须使用预加载脚本,并采用安全默认设置:contextIsolation: true、sandbox: true、nodeIntegration: false。
const mainWindow = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
// contextIsolation: true -- default since Electron 12
// sandbox: true -- default since Electron 20
// nodeIntegration: false -- default since Electron 5
},
});
要点: 切勿覆盖安全默认设置。预加载脚本是主进程与渲染进程之间唯一的桥梁。参见 examples/core.md。
模式 2:使用 contextBridge 的预加载脚本
预加载脚本向渲染进程暴露范围精简、明确声明类型的 API。切勿直接暴露 ipcRenderer。
// preload.js
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("electronAPI", {
readFile: (filePath) => ipcRenderer.invoke("read-file", filePath),
onUpdateAvailable: (callback) => {
ipcRenderer.on("update-available", (_event, data) => callback(data));
},
});
要点: 每个暴露的方法都封装一个 IPC 通道。渲染进程调用 window.electronAPI.readFile(path),无需了解 IPC 内部细节。参见 examples/core.md。
模式 3:IPC 请求-响应(invoke/handle)
在主进程中使用 ipcMain.handle(),在预加载脚本中使用 ipcRenderer.invoke(),实现异步双向通信。
// main process
ipcMain.handle("read-file", async (_event, filePath) => {
const content = await fs.readFile(filePath, "utf-8");
return { success: true, content };
});
要点: handle/invoke 会返回 Promise。务必在处理程序中验证 filePath——切勿信任渲染进程的输入。所有 IPC 模式参见 examples/ipc.md。
模式 4:主进程向渲染进程发送消息
在主进程中使用 webContents.send(),并在预加载脚本中通过回调模式监听。
// main: send to specific window
mainWindow.webContents.send("update-progress", { percent: 45 });
// preload: expose listener
onUpdateProgress: (callback) => {
ipcRenderer.on("update-progress", (_event, data) => callback(data));
},
要点: 渲染进程无法从主进程拉取消息——必须由主进程主动推送。监听器务必限定到特定通道。参见 examples/ipc.md。
模式 5:应用生命周期
主进程按照平台特定的惯例管理应用生命周期。
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
**要点:**关闭所有窗口后,macOS 应用仍会保持运行(window-all-closed 不应退出应用)。点击程序坞图标时,activate 事件会重新创建窗口。请参阅 examples/core.md。
模式 6:原生操作系统集成
Electron 提供了用于对话框、菜单、托盘图标、通知等功能的原生 API,均通过主进程访问。
const { dialog } = require("electron");
const result = await dialog.showOpenDialog(mainWindow, {
properties: ["openFile", "multiSelections"],
filters: [{ name: "Documents", extensions: ["txt", "md", "json"] }],
});
**要点:**将 mainWindow 作为第一个参数传入时,原生对话框会以该窗口为模态窗口。请参阅 examples/native-apis.md。
模式 7:自定义协议 / 深度链接
注册应用以处理 myapp:// URL,从浏览器或其他应用进行深度链接。
if (process.defaultApp) {
app.setAsDefaultProtocolClient("myapp", process.execPath, [
path.resolve(process.argv[1]),
]);
} else {
app.setAsDefaultProtocolClient("myapp");
}
**要点:**在开发环境中(process.defaultApp 为 true),必须将脚本路径作为参数传入。在 macOS 上,处理 app 对象上的 open-url 事件。在 Windows/Linux 上,通过 second-instance 事件处理。请参阅 examples/native-apis.md。
<decision_framework>
决策框架
IPC 模式选择
Which IPC pattern?
+-- Renderer needs a response from main?
| +-- YES --> ipcMain.handle() + ipcRenderer.invoke()
+-- Renderer sends data, no response needed?
| +-- YES --> ipcMain.on() + ipcRenderer.send()
+-- Main needs to push data to renderer?
| +-- YES --> webContents.send() + ipcRenderer.on() (in preload)
+-- Two renderers need to communicate?
| +-- YES --> Route through main process (never direct renderer-to-renderer)
+-- High-frequency data transfer (streaming)?
+-- YES --> MessageChannelMain / MessagePort pair
窗口架构
How many windows?
+-- Single window app?
| +-- One BrowserWindow, one preload script
+-- Multi-window (e.g., preferences, about)?
| +-- Separate BrowserWindow per view, each with its own preload
+-- Frameless / custom title bar?
| +-- frame: false + custom drag regions via CSS (-webkit-app-region: drag)
+-- Persistent background work?
+-- Use a hidden BrowserWindow or utilityProcess (Electron 22+)
</decision_framework>
详细资源:
- examples/core.md - 应用生命周期、BrowserWindow、preload、contextBridge 基础知识
- examples/ipc.md - 所有 IPC 模式:invoke/handle、send/on、主进程到渲染进程、MessagePort
- examples/security.md - 安全加固、CSP、权限处理器、安全默认设置
- examples/native-apis.md - 对话框、菜单、托盘、通知、协议处理器、自动更新程序
- examples/packaging.md - Electron Forge、Electron Builder、代码签名、分发
- reference.md - API 快速参考表、版本历史、安全检查清单
<red_flags>
严重问题
严重安全问题:
- 禁用
contextIsolation(contextIsolation: false)——会将 preload 全局变量暴露给渲染进程 - 启用
nodeIntegration: true——会让渲染进程获得完整的 Node.js 访问权限(fs、child_process 等) - 通过
contextBridge直接暴露ipcRenderer,而不是封装各个通道 - 未启用
sandbox: true就加载远程/不受信任的 URL - 在生产环境中禁用
webSecurity(webSecurity: false会禁用同源策略) - 未在主进程处理器中验证 IPC 参数(路径遍历、注入攻击)
- 使用
shell.openExternal()打开未经验证的 URL(可能执行任意命令)
架构问题:
- 使用
ipcRenderer.sendSync()——会阻塞渲染进程,导致界面卡顿 - 将业务逻辑放在渲染进程中,而不是主进程中
- 渲染进程之间直接通信(绕过主进程)
- 使用
remote模块(已在 Electron 14+ 中移除,存在安全和性能隐患) - 从渲染进程创建 BrowserWindow
- 未按平台处理
window-all-closed(macOS 应用不应退出)
打包问题:
- 在生产构建中包含
devDependencies(导致应用体积臃肿) - 未对应用进行代码签名(导致操作系统警告,并使 macOS 上的自动更新失败)
- 打包
node_modules时未进行精简或使用 ASAR 归档 - 硬编码在开发环境和打包环境中各不相同的绝对路径
- 在渲染进程代码中使用
__dirname(沙盒化的渲染进程中不可用)
常见错误:
- 忘记调用
app.whenReady()——ready事件触发前 API 不可用 - 未在
activate事件中重新创建窗口(点击 macOS 程序坞图标无效果) - 在通过
<script>标签加载的渲染进程脚本中使用require()(沙盒化的渲染进程中不可用) - 对加载外部内容的 iframe 设置
nodeIntegrationInSubFrames: true - 未为渲染进程 HTML 设置适当的
Content-Security-Policy标头
</red_flags>
<critical_reminders>
关键提醒
(你必须保持 contextIsolation: true(默认值)——禁用它会将整个 preload 作用域暴露给不可信的渲染器代码)
(你必须在 preload 脚本中使用 contextBridge.exposeInMainWorld()——绝不要直接暴露 ipcRenderer)
(你绝不能在任何 BrowserWindow 中启用 nodeIntegration: true——这会让渲染器获得完整的 Node.js 访问权限,造成严重的安全漏洞)
(你必须在主进程中验证并清理通过 IPC 接收的所有数据——将渲染器消息视为不可信输入)
(你必须使用 ipcMain.handle() / ipcRenderer.invoke() 实现请求-响应式 IPC——避免使用会阻塞渲染器的 sendSync)
不遵守这些规则会造成严重的安全漏洞,或导致桌面应用无法正常运行。
</critical_reminders>