mcpField
E
electron-scaffold

electron-scaffold

github.com/chrisvoncsefalvay開発382 回インストール54 週間前に更新
リポジトリ

electron-scaffold について

Electronデスクトップアプリの新規構築や既存構成の改善を支援するスキルです。ビルドツールやフロントエンドの選定に加え、セキュリティ、IPC、ネイティブUI、開発、パッケージングを扱います。

主な機能

  1. 01ビルドツールとフロントエンドを選定
  2. 02安全なElectronとIPCの構成
  3. 03開発・ビルドワークフローの設定
  4. 04ネイティブUIとアプリのパッケージング

活用シーン

  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 app」「desktop app」「cross-platform app」などに言及している
  • ユーザーが既存の 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 ファーストのアプローチ
  • ホットモジュールリプレースメント
  • 最適な用途:モダンなウェブフレームワーク(React、Vue、Svelte)、速度を重視した開発
2. フロントエンドフレームワーク

UI フレームワークを決定します。

  • Vanilla 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 ハンドラーで入力が検証されている
  • サンドボックスモードが有効になっている
  • ウェブセキュリティが有効になっている
  • ナビゲーションとリダイレクトのガードがある
パフォーマンス
  • レンダラーモジュールに遅延読み込みを採用している
  • バックグラウンドのスロットリングが設定されている
  • 大規模なデータセットに対するメモリ管理がある
  • 効率的な 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 固有のメニュー項目(About、Preferences)を検討する
  • 配布にはコード署名が必要
Windows
  • .ico アイコン形式を使用する
  • Squirrel の起動イベントを処理する
  • Windows のトースト通知を検討する
  • 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 リリースによる自動更新
  • ネイティブ UI 要素(メニュー、トレイ)
  • エラートラッキング
  • アナリティクス(任意)
  • クラッシュレポート
  • マルチプラットフォームのビルドパイプライン

成功のためのヒント

  1. 最初からセキュリティを確保する:セキュリティ対策を後回しにせず、初日から組み込みます
  2. すべてに型を付ける:メインプロセスとレンダラープロセスの両方で TypeScript を使用します
  3. IPC を早期にテストする:IPC の問題は早期のほうがデバッグしやすくなります
  4. プラットフォームをテストする:対象のすべてのプラットフォームで定期的にテストします
  5. バンドルサイズを監視する:レンダラーのバンドルを最適化された状態に保ちます
  6. IPC の契約を文書化する:プロセス間の API ドキュメントを維持します
  7. バージョン管理する:Git で dist/、node_modules/、.env を無視します
  8. プロセスマネージャーを使用する:メインプロセスのクラッシュを適切に処理します
  9. ロギングを実装する:構造化ロギングは本番環境の問題のデバッグに役立ちます
  10. 更新を計画する:最初のリリース前に更新戦略を設計します

避けるべきよくある落とし穴

  • ❌ 正当な理由なく nodeIntegration を有効にする
  • ❌ コンテキスト分離を省略する
  • ❌ 検証せずにリモートコンテンツを読み込む
  • ❌ IPC レンダラー全体を Web コンテンツに公開する
  • ❌ コンソールのセキュリティ警告を無視する
  • ❌ 対象のすべてのプラットフォームでテストしない
  • ❌ ファイルパスをハードコードする(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 ドキュメントを確認してください。

コメント