mcpField
E
electron-scaffold

electron-scaffold

github.com/chrisvoncsefalvay开发382 次安装54 周前更新
代码仓库

关于 electron-scaffold

一项用于搭建或改造 Electron 桌面应用的技能,指导选择构建工具与前端框架,并涵盖安全、IPC、本机界面、开发和打包实践。

主要功能

  1. 01选择构建工具与前端框架
  2. 02配置安全的 Electron 与 IPC 模式
  3. 03设置开发及构建工作流
  4. 04指导本机界面与应用打包

适用场景

  1. 01启动新的 Electron 桌面应用
  2. 02改造现有 Electron 项目
  3. 03准备跨平台应用的打包

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chrisvoncsefalvay/claude-skills --skill electron-scaffold

安装后在 Claude Code 中输入/electron-scaffold确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
build-config.md
electron-security.md
ipc-patterns.md
scripts/
scaffold.sh

详细介绍

Electron 应用脚手架搭建

从一开始就内置安全性、性能和原生平台集成方面的最佳实践,创建可用于生产环境的 Electron 应用。

何时使用此技能

在以下情况下使用此技能:

  • 用户想要创建新的 Electron 桌面应用
  • 用户需要按照现代最佳实践搭建 Electron 项目
  • 用户想要外观原生的跨平台桌面应用
  • 用户提到“Electron 应用”“桌面应用”“跨平台应用”等类似说法
  • 用户想要更新现有 Electron 项目的结构

前置条件检查

搭建脚手架前,请确认:

  1. Node.js:检查 Node.js 版本(建议使用 18.x 或更高版本)

    node --version
    
  2. npm 或 yarn:确认包管理器可用

    npm --version
    
  3. Git:确保 Git 可用于版本控制

    git --version
    

架构决策要点

1. 构建工具选择

询问用户偏好的构建系统(或根据使用场景给出建议):

Electron Forge(大多数项目的推荐选择)

  • 一体化工具解决方案
  • 内置 TypeScript 支持
  • 易于使用的插件系统
  • 适用于:大多数新项目,以及希望开箱即用的团队

Electron Builder

  • 高度可配置
  • 出色的多平台打包能力
  • 支持自动更新
  • 适用于:复杂的构建需求、特定的打包需求

Vite + Electron

  • 最快的开发体验
  • 现代化、以 ESM 为先的方案
  • 热模块替换
  • 适用于:现代 Web 框架(React、Vue、Svelte)以及注重开发速度的场景
2. 前端框架

确定 UI 框架:

  • 原生 JS/TypeScript:最轻量,完全掌控
  • React:最受欢迎,生态系统庞大
  • Vue:渐进式,易于学习
  • Svelte:包体积最小,编译时框架
  • Angular:适用于企业,具有明确的设计主张
3. TypeScript 还是 JavaScript

强烈建议使用 TypeScript,以便:

  • 获得更好的 IDE 支持和自动补全
  • 在编译时捕获错误
  • 提高可维护性
  • 获得 Electron API 类型支持

工作流

第 1 步:初始化项目

根据所选工具初始化项目:

使用 Electron Forge(推荐):

npm init electron-app@latest <app-name> -- --template=webpack-typescript

使用 Vite + Electron:

npm create @quick-start/electron <app-name>

使用自定义方案: 创建 package.json 并添加适当的依赖项(参见模板)。

第 2 步:设置项目结构

创建条理清晰的项目结构:

<app-name>/
├── src/
│   ├── main/              # Main process
│   │   ├── main.ts        # Entry point
│   │   ├── ipc/           # IPC handlers
│   │   ├── menu.ts        # Native menu
│   │   └── tray.ts        # System tray (if needed)
│   ├── preload/           # Preload scripts
│   │   └── preload.ts     # Context bridge
│   ├── renderer/          # Renderer process
│   │   ├── index.html
│   │   ├── index.ts
│   │   └── styles/
│   └── shared/            # Shared types/utilities
│       └── types.ts
├── assets/                # Icons, images
├── resources/             # Build resources
├── dist/                  # Build output
├── package.json
├── tsconfig.json
└── electron-builder.yml   # or forge.config.js
第 3 步:安全配置

重要:从一开始就实施安全最佳实践。

1. BrowserWindow 安全选项:

const mainWindow = new BrowserWindow({
  width: 1200,
  height: 800,
  webPreferences: {
    // Security: Use preload scripts instead of nodeIntegration
    nodeIntegration: false,
    // Security: Isolate context between web content and preload
    contextIsolation: true,
    // Security: Disable remote module
    enableRemoteModule: false,
    // Security: Use sandboxed renderer
    sandbox: true,
    // Preload script for safe IPC
    preload: path.join(__dirname, 'preload.js'),
    // Security: Disable web security only in development if needed
    webSecurity: true,
    // Security: Disable navigation
    allowRunningInsecureContent: false,
  },
});

2. 内容安全策略(CSP):

// In main process or HTML meta tag
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
  callback({
    responseHeaders: {
      ...details.responseHeaders,
      'Content-Security-Policy': [
        "default-src 'self'",
        "script-src 'self'",
        "style-src 'self' 'unsafe-inline'",
        "img-src 'self' data: https:",
        "connect-src 'self'",
      ].join('; '),
    },
  });
});

3. 上下文桥接(preload.ts):

import { contextBridge, ipcRenderer } from 'electron';

// Expose protected methods that allow the renderer process to use
// the ipcRenderer without exposing the entire object
contextBridge.exposeInMainWorld('electronAPI', {
  // Invoke pattern (request-response)
  getAppVersion: () => ipcRenderer.invoke('app:get-version'),

  // Send pattern (one-way)
  logMessage: (message: string) => ipcRenderer.send('log:message', message),

  // Listener pattern (for receiving events)
  onUpdateAvailable: (callback: (info: any) => void) => {
    ipcRenderer.on('update:available', (_event, info) => callback(info));
  },

  // Remove listener
  removeUpdateListener: () => {
    ipcRenderer.removeAllListeners('update:available');
  },
});

4. IPC 安全模式:

// main/ipc/handlers.ts
import { ipcMain } from 'electron';

// Use invoke/handle pattern for request-response
ipcMain.handle('app:get-version', async () => {
  return app.getVersion();
});

// Validate and sanitize all inputs
ipcMain.handle('file:read', async (_event, filePath: string) => {
  // Validate path is within allowed directories
  const allowedDir = app.getPath('userData');
  const resolvedPath = path.resolve(filePath);

  if (!resolvedPath.startsWith(allowedDir)) {
    throw new Error('Access denied');
  }

  return fs.readFile(resolvedPath, 'utf-8');
});
第 4 步:原生 UI 元素

创建外观原生的 UI 组件:

1. 应用菜单:

// main/menu.ts
import { Menu, shell } from 'electron';

export function createApplicationMenu(mainWindow: BrowserWindow) {
  const template: MenuItemConstructorOptions[] = [
    {
      label: 'File',
      submenu: [
        {
          label: 'New',
          accelerator: 'CmdOrCtrl+N',
          click: () => mainWindow.webContents.send('file:new'),
        },
        { type: 'separator' },
        { role: 'quit' },
      ],
    },
    {
      label: 'Edit',
      submenu: [
        { role: 'undo' },
        { role: 'redo' },
        { type: 'separator' },
        { role: 'cut' },
        { role: 'copy' },
        { role: 'paste' },
      ],
    },
    {
      label: 'View',
      submenu: [
        { role: 'reload' },
        { role: 'forceReload' },
        { role: 'toggleDevTools' },
        { type: 'separator' },
        { role: 'resetZoom' },
        { role: 'zoomIn' },
        { role: 'zoomOut' },
        { type: 'separator' },
        { role: 'togglefullscreen' },
      ],
    },
    {
      label: 'Help',
      submenu: [
        {
          label: 'Learn More',
          click: async () => {
            await shell.openExternal('https://electronjs.org');
          },
        },
      ],
    },
  ];

  const menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
}

2. 系统托盘(可选):

// main/tray.ts
import { Tray, Menu, nativeImage } from 'electron';

export function createTray(mainWindow: BrowserWindow) {
  const icon = nativeImage.createFromPath(
    path.join(__dirname, '../assets/tray-icon.png')
  );

  const tray = new Tray(icon);

  const contextMenu = Menu.buildFromTemplate([
    {
      label: 'Show App',
      click: () => {
        mainWindow.show();
      },
    },
    {
      label: 'Quit',
      click: () => {
        app.quit();
      },
    },
  ]);

  tray.setContextMenu(contextMenu);
  tray.setToolTip('My Electron App');

  return tray;
}
第 5 步:设置开发环境

1. 热重载配置:

// main.ts
const isDevelopment = process.env.NODE_ENV === 'development';

if (isDevelopment) {
  mainWindow.loadURL('http://localhost:5173'); // Vite dev server
  mainWindow.webContents.openDevTools();
} else {
  mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'));
}

2. package.json 脚本:

{
  "scripts": {
    "dev": "concurrently \"npm:dev:*\"",
    "dev:vite": "vite",
    "dev:electron": "electron .",
    "build": "npm run build:renderer && npm run build:main",
    "build:renderer": "vite build",
    "build:main": "tsc -p tsconfig.main.json",
    "package": "electron-builder",
    "package:all": "electron-builder -mwl",
    "lint": "eslint src --ext .ts,.tsx",
    "typecheck": "tsc --noEmit"
  }
}
第 6 步:自动更新配置

使用 electron-updater 实现自动更新:

1. 安装依赖项:

npm install electron-updater

2. 更新配置:

// main/updater.ts
import { autoUpdater } from 'electron-updater';

export function setupAutoUpdater(mainWindow: BrowserWindow) {
  // Configure update server
  autoUpdater.setFeedURL({
    provider: 'github',
    owner: 'your-username',
    repo: 'your-repo',
  });

  // Check for updates on startup
  autoUpdater.checkForUpdatesAndNotify();

  // Update events
  autoUpdater.on('update-available', (info) => {
    mainWindow.webContents.send('update:available', info);
  });

  autoUpdater.on('update-downloaded', (info) => {
    mainWindow.webContents.send('update:downloaded', info);
  });

  autoUpdater.on('error', (err) => {
    mainWindow.webContents.send('update:error', err);
  });
}

3. electron-builder 配置:

# electron-builder.yml
appId: com.yourcompany.yourapp
productName: YourApp
directories:
  output: dist
  buildResources: resources
files:
  - src/**/*
  - package.json
mac:
  category: public.app-category.productivity
  target:
    - dmg
    - zip
  hardenedRuntime: true
  gatekeeperAssess: false
  entitlements: resources/entitlements.mac.plist
win:
  target:
    - nsis
    - portable
  publisherName: Your Company
linux:
  target:
    - AppImage
    - deb
  category: Utility
publish:
  provider: github
  owner: your-username
  repo: your-repo
第 7 步:TypeScript 配置

tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "lib": ["ES2020", "DOM"],
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "types": ["node", "electron"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}
第 8 步:构建和打包

开发环境:

npm run dev

生产构建:

npm run build
npm run package

多平台构建:

npm run package:all

最佳实践检查清单

搭建脚手架时,请确保实现以下内容:

安全性
  • 已启用上下文隔离
  • 已在渲染进程中禁用 Node 集成
  • 使用上下文桥接的预加载脚本
  • 已配置内容安全策略
  • 对所有 IPC 处理程序进行输入验证
  • 已启用沙箱模式
  • 已启用 Web 安全
  • 已设置导航和重定向防护
性能
  • 对渲染进程模块进行延迟加载
  • 已配置后台节流
  • 对大型数据集进行内存管理
  • 使用高效的 IPC 模式(批量更新)
  • 优化 Webpack/Vite
用户体验
  • 原生应用菜单
  • 键盘快捷键(加速键)
  • 窗口状态持久化
  • 完整的图标集(所有尺寸)
  • 启动画面(可选)
  • 错误边界
  • 加载状态
开发体验
  • 已配置 TypeScript
  • 热重载正常工作
  • 开发环境中可使用 DevTools
  • 已配置 ESLint 和 Prettier
  • 使用 Husky 配置 Git 钩子(可选)
  • 已启用源映射
分发
  • 已配置自动更新
  • 已配置代码签名(因平台而异)
  • 已为所有平台配置构建脚本
  • 完整的应用元数据
  • 已包含许可证文件

错误处理模式

主进程错误
process.on('uncaughtException', (error) => {
  console.error('Uncaught Exception:', error);
  // Log to file or error tracking service
  app.quit();
});

process.on('unhandledRejection', (reason) => {
  console.error('Unhandled Rejection:', reason);
});
渲染进程错误
window.addEventListener('error', (event) => {
  window.electronAPI.logError({
    message: event.error.message,
    stack: event.error.stack,
  });
});

window.addEventListener('unhandledrejection', (event) => {
  window.electronAPI.logError({
    message: 'Unhandled Promise Rejection',
    reason: event.reason,
  });
});

平台特定注意事项

macOS
  • 使用 .icns 图标格式
  • 实现 Dock 菜单
  • 处理 activate 事件(重新打开窗口)
  • 考虑 macOS 特定菜单项(关于、偏好设置)
  • 分发时需要代码签名
Windows
  • 使用 .ico 图标格式
  • 处理 Squirrel 启动事件
  • 考虑 Windows Toast 通知
  • 自定义 NSIS 安装程序
  • 使用证书进行代码签名
Linux
  • 使用 .png 图标格式
  • 提供 .desktop 文件
  • 处理不同的软件包格式(deb、AppImage、snap)
  • 在多个发行版上测试

示例脚手架

最简 TypeScript 配置
# Initialize with Forge
npm init electron-app@latest my-app -- --template=webpack-typescript

# Add security defaults
# Add IPC patterns
# Configure build
React + TypeScript + Vite
# Create with Vite template
npm create @quick-start/electron my-app -- --template react-ts

# Add security hardening
# Configure auto-update
# Add native menus
可用于生产环境的完整配置
  • 完整的安全配置
  • 通过 GitHub Releases 自动更新
  • 原生 UI 元素(菜单、托盘)
  • 错误跟踪
  • 分析(可选)
  • 崩溃报告
  • 多平台构建流水线

成功提示

  1. 从一开始就确保安全:不要等到之后才添加安全措施——从第一天起就将其纳入设计
  2. 为所有内容添加类型:在主进程和渲染进程中都使用 TypeScript
  3. 尽早测试 IPC:尽早发现的 IPC 问题更容易调试
  4. 进行平台测试:定期在所有目标平台上测试
  5. 监控包大小:确保渲染进程的包经过优化
  6. 记录 IPC 契约:维护进程间的 API 文档
  7. 版本控制:在 Git 中忽略 dist/、node_modules/、.env
  8. 使用进程管理器:妥善处理主进程崩溃
  9. 实现日志记录:结构化日志有助于调试生产环境中的问题
  10. 规划更新:在首次发布前设计更新策略

应避免的常见问题

  • ❌ 无充分理由启用 nodeIntegration
  • ❌ 跳过上下文隔离
  • ❌ 未经验证就加载远程内容
  • ❌ 向网页内容暴露整个 IPC 渲染器
  • ❌ 忽略控制台中的安全警告
  • ❌ 未在所有目标平台上进行测试
  • ❌ 将文件路径硬编码(使用 app.getPath())
  • ❌ 忘记处理窗口状态持久化
  • ❌ 未实现恰当的错误边界
  • ❌ 分发时跳过代码签名

快速入门命令

对于大多数用户,建议使用以下命令:

# Create app with TypeScript and Webpack
npm init electron-app@latest <app-name> -- --template=webpack-typescript

# Then apply security hardening, native UI, and build configuration

参考文件

如需详细的 Electron API 示例和配置模板,请参阅:

  • references/electron-security.md - 安全最佳实践
  • references/ipc-patterns.md - IPC 通信模式
  • references/build-config.md - 构建和打包配置
  • scripts/scaffold.sh - 自动化脚手架脚本

脚手架生成后的检查清单

完成脚手架生成后,引导用户:

  1. ✅ 检查并自定义 package.json 元数据
  2. ✅ 添加应用图标(适用于所有平台)
  3. ✅ 配置代码签名证书
  4. ✅ 设置用于自动更新的 GitHub 仓库
  5. ✅ 测试热重载和开发工作流
  6. ✅ 为所有目标平台构建
  7. ✅ 测试更新机制
  8. ✅ 检查安全设置
  9. ✅ 添加错误跟踪(Sentry 等)
  10. ✅ 创建用户文档

版本兼容性

此技能面向:

  • Electron:v28+(最新稳定版)
  • Node.js:v18+ LTS
  • TypeScript:v5+
  • Electron Forge:v7+
  • Electron Builder:v24+

请始终查阅最新的 Electron 文档,了解可能导致不兼容的变更。

评论

支持 Markdown