electron-best-practices by jwynia/agent-skills
npx skills add https://github.com/jwynia/agent-skills --skill electron-best-practices指导 AI 代理构建安全、可用于生产的 Electron 应用程序(使用 React)。此技能提供安全模式、类型安全的 IPC 通信、项目设置指南、打包和代码签名工作流,以及用于分析、脚手架和类型生成的工具。
在以下情况下使用此技能:
在以下情况下不要使用此技能:
现代 Electron 安全依赖于在 Electron 20+ 中成为标准的三个默认设置:上下文隔离、沙箱模式和禁用 nodeIntegration。禁用其中任何一个都会导致 XSS 攻击升级为完整的远程代码执行。所有主进程-渲染器通信都必须通过 contextBridge 进行:
// preload.ts - 安全模式
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
onUpdateCounter: (callback: (value: number) => void) => {
const handler = (_event: IpcRendererEvent, value: number) => callback(value);
ipcRenderer.on('update-counter', handler);
return () => ipcRenderer.removeListener('update-counter', handler);
}
});
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
对于加载本地文件的应用,通过 HTTP 头设置内容安全策略,将脚本源限制为 'self'。
对于请求-响应通信,invoke/handle 模式优于 send/on,它提供了正确的 async/await 语义和错误传播。对于类型化的通道,使用映射类型模式:
type IpcChannelMap = {
'load-prefs': { args: []; return: UserPreferences };
'save-file': { args: [content: string]; return: { success: boolean } };
};
对于复杂的应用程序,electron-trpc 使用 tRPC 的路由器模式和 Zod 验证提供了完整的类型安全:
export const appRouter = t.router({
greeting: t.procedure
.input(z.object({ name: z.string() }))
.query(({ input }) => `Hello, ${input.name}!`),
});
跨 IPC 边界的错误处理需要特别注意,因为 Electron 只序列化 Error 对象的 message 属性。将响应包装在 { success, data, error } 结果类型中,以保留完整的错误上下文。
推荐的堆栈使用 electron-vite 进行开发,使用 Electron Forge 进行打包。electron-vite 提供了一个统一的配置,管理主进程、预加载脚本和渲染器进程,具有亚秒级的开发服务器启动时间和即时 HMR。Electron Forge 使用官方的 Electron 包进行签名和公证。
src/
├── main/ # 主进程 (Node.js 环境)
│ ├── index.ts
│ └── ipc/ # IPC 处理程序
├── preload/ # 通过 contextBridge 的安全桥接
│ ├── index.ts
│ └── index.d.ts # 暴露 API 的 TypeScript 声明
└── renderer/ # React 应用程序 (纯 Web,无 Node 访问权限)
├── src/
└── index.html
React 18 的并发特性在 Electron 基于 Chromium 的渲染器中正常工作。严格模式对副作用函数的双重调用可以捕获 IPC 监听器泄漏,否则会导致内存问题。始终从注册 IPC 监听器的副作用函数中返回清理函数:
useEffect(() => {
const cleanup = window.electronAPI.onUpdateCounter((value) => {
setCount(value);
});
return cleanup;
}, []);
对于多窗口应用程序,主进程应作为共享状态的单一事实来源。使用 electron-store 进行持久化,并结合 IPC 广播,以便任何窗口的修改都能更新所有其他窗口。
| 类别 | 推荐 | 避免 |
|---|---|---|
| 安全 | contextBridge.exposeInMainWorld() | nodeIntegration: true |
| IPC | invoke/handle 模式 | 对请求-响应使用 send/on |
| 预加载脚本 | 类型化的函数包装器 | 暴露原始的 ipcRenderer |
| 构建工具 | electron-vite | 基于 webpack 的工具链 |
| 打包 | Electron Forge | 手动打包 |
| 状态管理 | Zustand + electron-store | 对简单应用使用 Redux |
| 测试 | Playwright E2E | Spectron (已弃用) |
| 更新 | electron-updater | 手动检查更新 |
| 签名 | CI 集成的代码签名 | 未签名的发布版本 |
| CSP | HTTP 头,仅限 'self' | 无 CSP |
| 错误处理 | 结果类型 {success, data, error} | 跨 IPC 传递原始 Error |
| 多窗口 | 主进程作为状态中心 | 窗口间直接通信 |
生成 Electron 代码时,请遵循以下模式:
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
sandbox: true,
nodeIntegration: false,
},
});
始终启用 contextIsolation 和 sandbox。切勿启用 nodeIntegration。预加载脚本路径必须解析到构建输出位置。
export function registerFileHandlers(): void {
ipcMain.handle('save-file', async (_event, content: string) => {
try {
await fs.writeFile(filePath, content);
return { success: true, data: filePath };
} catch (err) {
return { success: false, error: (err as Error).message };
}
});
}
将相关的处理程序分组到模块中。对所有返回值使用结果类型模式。验证从渲染器进程接收的所有参数。
生成 Electron 代码时避免以下模式:
| 反模式 | 问题 | 解决方案 |
|---|---|---|
nodeIntegration: true | XSS 升级为完整 RCE | 保持禁用(默认) |
直接暴露 ipcRenderer | 渲染器拥有完整的 IPC 访问权限 | 包装在 contextBridge 函数中 |
缺少 contextIsolation | 渲染器访问预加载脚本作用域 | 保持启用(自 Electron 12 起默认) |
| 无代码签名 | 操作系统安全警告,Gatekeeper 阻止 | 为所有平台签名和公证 |
BrowserWindow 无沙箱 | 预加载脚本拥有完整的 Node.js 访问权限 | 启用沙箱(自 Electron 20 起默认) |
| 未验证的 IPC 参数 | 来自渲染器的注入攻击 | 使用 Zod 或手动检查进行验证 |
0.0.0.0 服务器绑定 | 网络暴露的本地服务器 | 始终绑定到 127.0.0.1 |
| 缺少 CSP 头 | 脚本注入向量 | 通过 HTTP 头设置严格的 CSP |
| 无 IPC 错误序列化 | 跨边界丢失错误上下文 | 使用结果类型模式 |
| 使用 Spectron 测试 | 已弃用,最高支持 Electron 13 | 使用 Playwright |
完整的安全审计清单请参见 references/security/security-checklist.md。
分析 Electron 项目中的安全错误配置:
deno run --allow-read scripts/analyze-security.ts <path> [options]
选项:
--strict 启用所有检查
--json 为 CI 输出 JSON
-h, --help 显示帮助
示例:
# 分析一个项目
deno run --allow-read scripts/analyze-security.ts ./src
# CI 流水线的严格模式
deno run --allow-read scripts/analyze-security.ts ./src --strict --json
使用安全默认值搭建一个新的 Electron + React 项目:
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts [options]
选项:
--name <name> 应用名称 (必需)
--path <path> 目标目录 (默认: ./)
--with-react 包含 React 设置
--with-trpc 包含 electron-trpc
--with-tests 包含 Playwright 测试
示例:
# 包含 React 的基础应用
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react
# 包含 trpc 和测试的完整设置
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react --with-trpc --with-tests
从 IPC 处理程序文件生成 TypeScript 类型定义:
deno run --allow-read --allow-write scripts/generate-ipc-types.ts [options]
选项:
--handlers <path> IPC 处理程序文件路径
--output <path> 类型定义的输出路径
--validate 验证现有类型是否与处理程序匹配
示例:
# 从处理程序生成类型
deno run --allow-read --allow-write scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --output ./src/preload/ipc-types.d.ts
# 在 CI 中验证类型
deno run --allow-read scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --validate
references/security/context-isolation.md - contextBridge 和隔离模式references/security/csp-and-permissions.md - 内容安全策略配置references/security/security-checklist.md - 完整的安全审计清单references/ipc/typed-ipc.md - 类型化通道映射模式references/ipc/electron-trpc.md - 实现完整类型安全的 tRPC 集成references/ipc/error-serialization.md - 跨 IPC 边界的结果类型references/architecture/project-structure.md - 目录组织references/architecture/process-separation.md - 主进程、预加载脚本和渲染器进程的角色references/architecture/multi-window-state.md - 跨窗口的共享状态references/integration/react-patterns.md - useEffect 清理、严格模式references/integration/state-management.md - Zustand 和 electron-store 模式references/packaging/code-signing.md - 平台特定的签名工作流references/packaging/auto-updates.md - electron-updater 配置references/packaging/bundle-optimization.md - 大小优化技术references/packaging/ci-cd-patterns.md - GitHub Actions 矩阵构建references/testing/playwright-e2e.md - Playwright Electron 支持references/testing/unit-testing.md - Jest/Vitest 多项目配置references/testing/test-structure.md - 测试组织模式references/tooling/electron-vite.md - 构建工具配置references/tooling/electron-forge.md - 打包和分发references/tooling/tauri-comparison.md - 何时选择 Tauriassets/templates/main-process.ts.md - 主进程启动模板assets/templates/preload-script.ts.md - 使用 contextBridge 的预加载脚本模板assets/templates/ipc-handler.ts.md - IPC 处理程序模块模板assets/templates/react-root.tsx.md - React 根组件模板assets/configs/electron-vite.config.ts.md - electron-vite 配置assets/configs/forge.config.js.md - Electron Forge 配置assets/configs/tsconfig.json.md - TypeScript 配置预设assets/configs/playwright.config.ts.md - Playwright Electron 测试配置assets/examples/typed-ipc-example.md - 端到端类型化 IPC 演练assets/examples/multi-window-example.md - 多窗口状态管理每周安装量
148
仓库
GitHub Stars
37
首次出现
2026年2月4日
安全审计
安装于
codex142
opencode140
gemini-cli139
github-copilot137
cursor132
kimi-cli131
Guide AI agents in building secure, production-ready Electron applications with React. This skill provides security patterns, type-safe IPC communication, project setup guidance, packaging and code signing workflows, and tools for analysis, scaffolding, and type generation.
Use this skill when:
Do NOT use this skill when:
Modern Electron security relies on three defaults that became standard in Electron 20+: context isolation, sandbox mode, and nodeIntegration disabled. Disabling any of them allows XSS attacks to escalate to full remote code execution. All main-renderer communication must flow through contextBridge:
// preload.ts - SECURE pattern
contextBridge.exposeInMainWorld('electronAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs'),
saveFile: (content: string) => ipcRenderer.invoke('save-file', content),
onUpdateCounter: (callback: (value: number) => void) => {
const handler = (_event: IpcRendererEvent, value: number) => callback(value);
ipcRenderer.on('update-counter', handler);
return () => ipcRenderer.removeListener('update-counter', handler);
}
});
Set Content Security Policy via HTTP headers for apps loading local files, restricting script sources to 'self'.
The invoke/handle pattern is preferred over send/on for request-response communication, providing proper async/await semantics and error propagation. For typed channels, use a mapped type pattern:
type IpcChannelMap = {
'load-prefs': { args: []; return: UserPreferences };
'save-file': { args: [content: string]; return: { success: boolean } };
};
For complex applications, electron-trpc provides full type safety using tRPC's router pattern with Zod validation:
export const appRouter = t.router({
greeting: t.procedure
.input(z.object({ name: z.string() }))
.query(({ input }) => `Hello, ${input.name}!`),
});
Error handling across the IPC boundary requires attention because Electron only serializes the message property of Error objects. Wrap responses in a { success, data, error } result type to preserve full error context.
The recommended stack uses electron-vite for development and Electron Forge for packaging. electron-vite provides a unified configuration managing main, preload, and renderer processes with sub-second dev server startup and instant HMR. Electron Forge uses first-party Electron packages for signing and notarization.
src/
├── main/ # Main process (Node.js environment)
│ ├── index.ts
│ └── ipc/ # IPC handlers
├── preload/ # Secure bridge via contextBridge
│ ├── index.ts
│ └── index.d.ts # TypeScript declarations for exposed APIs
└── renderer/ # React application (pure web, no Node access)
├── src/
└── index.html
React 18's concurrent features work normally in Electron's Chromium-based renderer. Strict Mode's double-invocation of effects catches IPC listener leaks that would otherwise cause memory issues. Always return cleanup functions from effects that register IPC listeners:
useEffect(() => {
const cleanup = window.electronAPI.onUpdateCounter((value) => {
setCount(value);
});
return cleanup;
}, []);
For multi-window applications, the main process should serve as the single source of truth for shared state. Use electron-store for persistence combined with IPC broadcasting so any window's mutation updates all others.
| Category | Prefer | Avoid |
|---|---|---|
| Security | contextBridge.exposeInMainWorld() | nodeIntegration: true |
| IPC | invoke/handle pattern | send/on for request-response |
| Preload | Typed function wrappers | Exposing raw ipcRenderer |
| Build tool | electron-vite | webpack-based toolchains |
| Packaging | Electron Forge |
When generating Electron code, follow these patterns:
const win = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, '../preload/index.js'),
contextIsolation: true,
sandbox: true,
nodeIntegration: false,
},
});
Always enable contextIsolation and sandbox. Never enable nodeIntegration. The preload path must resolve to the built output location.
export function registerFileHandlers(): void {
ipcMain.handle('save-file', async (_event, content: string) => {
try {
await fs.writeFile(filePath, content);
return { success: true, data: filePath };
} catch (err) {
return { success: false, error: (err as Error).message };
}
});
}
Group related handlers into modules. Use the result type pattern for all return values. Validate all arguments received from the renderer process.
Avoid these patterns when generating Electron code:
| Anti-Pattern | Problem | Solution |
|---|---|---|
nodeIntegration: true | XSS escalates to full RCE | Keep disabled (default) |
Exposing ipcRenderer directly | Full IPC access from renderer | Wrap in contextBridge functions |
Missing contextIsolation | Renderer accesses preload scope | Keep enabled (default since Electron 12) |
| No code signing | OS security warnings, Gatekeeper blocks | Sign and notarize for all platforms |
BrowserWindow without sandbox | Preload has full Node.js access | Enable sandbox (default since Electron 20) |
See references/security/security-checklist.md for the full security audit checklist.
Analyze Electron projects for security misconfigurations:
deno run --allow-read scripts/analyze-security.ts <path> [options]
Options:
--strict Enable all checks
--json Output JSON for CI
-h, --help Show help
Examples:
# Analyze a project
deno run --allow-read scripts/analyze-security.ts ./src
# Strict mode for CI pipeline
deno run --allow-read scripts/analyze-security.ts ./src --strict --json
Scaffold a new Electron + React project with secure defaults:
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts [options]
Options:
--name <name> App name (required)
--path <path> Target directory (default: ./)
--with-react Include React setup
--with-trpc Include electron-trpc
--with-tests Include Playwright tests
Examples:
# Basic app with React
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react
# Full setup with trpc and tests
deno run --allow-read --allow-write scripts/scaffold-electron-app.ts \
--name "my-app" --with-react --with-trpc --with-tests
Generate TypeScript type definitions from IPC handler files:
deno run --allow-read --allow-write scripts/generate-ipc-types.ts [options]
Options:
--handlers <path> Path to IPC handler files
--output <path> Output path for type definitions
--validate Validate existing types match handlers
Examples:
# Generate types from handlers
deno run --allow-read --allow-write scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --output ./src/preload/ipc-types.d.ts
# Validate types in CI
deno run --allow-read scripts/generate-ipc-types.ts \
--handlers ./src/main/ipc --validate
references/security/context-isolation.md - contextBridge and isolation patternsreferences/security/csp-and-permissions.md - Content Security Policy configurationreferences/security/security-checklist.md - Full security audit checklistreferences/ipc/typed-ipc.md - Typed channel map patternsreferences/ipc/electron-trpc.md - tRPC integration for full type safetyreferences/ipc/error-serialization.md - Result types across IPC boundaryreferences/architecture/project-structure.md - Directory organizationreferences/architecture/process-separation.md - Main, preload, and renderer rolesreferences/architecture/multi-window-state.md - Shared state across windowsreferences/integration/react-patterns.md - useEffect cleanup, Strict Modereferences/integration/state-management.md - Zustand and electron-store patternsreferences/packaging/code-signing.md - Platform-specific signing workflowsreferences/packaging/auto-updates.md - electron-updater configurationreferences/packaging/bundle-optimization.md - Size reduction techniquesreferences/packaging/ci-cd-patterns.md - GitHub Actions matrix buildsreferences/testing/playwright-e2e.md - Playwright Electron supportreferences/testing/unit-testing.md - Jest/Vitest multi-project configurationreferences/testing/test-structure.md - Test organization patternsreferences/tooling/electron-vite.md - Build tool configurationreferences/tooling/electron-forge.md - Packaging and distributionreferences/tooling/tauri-comparison.md - When to choose Tauri insteadassets/templates/main-process.ts.md - Main process starter templateassets/templates/preload-script.ts.md - Preload script with contextBridgeassets/templates/ipc-handler.ts.md - IPC handler module templateassets/templates/react-root.tsx.md - React root component templateassets/configs/electron-vite.config.ts.md - electron-vite configurationassets/configs/forge.config.js.md - Electron Forge configurationassets/configs/tsconfig.json.md - TypeScript configuration presetsassets/configs/playwright.config.ts.md - Playwright Electron test configassets/examples/typed-ipc-example.md - End-to-end typed IPC walkthroughassets/examples/multi-window-example.md - Multi-window state managementWeekly Installs
148
Repository
GitHub Stars
37
First Seen
Feb 4, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex142
opencode140
gemini-cli139
github-copilot137
cursor132
kimi-cli131
Azure RBAC 权限管理工具:查找最小角色、创建自定义角色与自动化分配
131,500 周安装
| Manual packaging |
| State | Zustand + electron-store | Redux for simple apps |
| Testing | Playwright E2E | Spectron (deprecated) |
| Updates | electron-updater | Manual update checks |
| Signing | CI-integrated code signing | Unsigned releases |
| CSP | HTTP headers, 'self' only | No CSP |
| Error handling | Result type {success, data, error} | Raw Error across IPC |
| Multi-window | Main process as state hub | Direct window-to-window |
| Unvalidated IPC arguments | Injection attacks from renderer | Validate with Zod or manual checks |
0.0.0.0 server binding | Network-exposed local server | Always bind to 127.0.0.1 |
| Missing CSP headers | Script injection vectors | Set strict CSP via HTTP headers |
| No IPC error serialization | Lost error context across boundary | Use Result type pattern |
| Spectron for testing | Deprecated, Electron 13 max | Use Playwright |