electron-scaffold について
Electronデスクトップアプリの新規構築や既存構成の改善を支援するスキルです。ビルドツールやフロントエンドの選定に加え、セキュリティ、IPC、ネイティブUI、開発、パッケージングを扱います。
主な機能
- 01ビルドツールとフロントエンドを選定
- 02安全なElectronとIPCの構成
- 03開発・ビルドワークフローの設定
- 04ネイティブUIとアプリのパッケージング
活用シーン
- 01新しいElectronデスクトップアプリの開始
- 02既存Electronプロジェクトの構成改善
- 03クロスプラットフォームアプリのパッケージ準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ chrisvoncsefalvay/ claude-skills --skill electron-scaffoldインストール後、Claude Code で/electron-scaffoldを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/build-config.mdelectron-security.mdipc-patterns.mdscripts/scaffold.sh詳細
Electron アプリケーションのスキャフォールディング
セキュリティ、パフォーマンス、ネイティブプラットフォームとの連携に関するベストプラクティスを最初から組み込んで、本番環境に対応できる Electron アプリケーションを作成します。
このスキルを使用する場面
次のような場合に、このスキルを使用します。
- ユーザーが新しい Electron デスクトップアプリケーションの作成を希望している
- ユーザーがモダンなベストプラクティスに沿って Electron プロジェクトをスキャフォールディングする必要がある
- ユーザーがネイティブな外観のクロスプラットフォームデスクトップアプリを希望している
- ユーザーが「Electron app」「desktop app」「cross-platform app」などに言及している
- ユーザーが既存の Electron プロジェクト構成をモダン化したいと考えている
前提条件の確認
スキャフォールディングの前に、以下を確認します。
-
Node.js:Node.js のバージョンを確認します(18.x 以上を推奨)
node --version -
npm または yarn:パッケージマネージャーが利用可能であることを確認します
npm --version -
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 要素(メニュー、トレイ)
- エラートラッキング
- アナリティクス(任意)
- クラッシュレポート
- マルチプラットフォームのビルドパイプライン
成功のためのヒント
- 最初からセキュリティを確保する:セキュリティ対策を後回しにせず、初日から組み込みます
- すべてに型を付ける:メインプロセスとレンダラープロセスの両方で TypeScript を使用します
- IPC を早期にテストする:IPC の問題は早期のほうがデバッグしやすくなります
- プラットフォームをテストする:対象のすべてのプラットフォームで定期的にテストします
- バンドルサイズを監視する:レンダラーのバンドルを最適化された状態に保ちます
- IPC の契約を文書化する:プロセス間の API ドキュメントを維持します
- バージョン管理する:Git で
dist/、node_modules/、.envを無視します - プロセスマネージャーを使用する:メインプロセスのクラッシュを適切に処理します
- ロギングを実装する:構造化ロギングは本番環境の問題のデバッグに役立ちます
- 更新を計画する:最初のリリース前に更新戦略を設計します
避けるべきよくある落とし穴
- ❌ 正当な理由なく
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- 自動スキャフォールドスクリプト
スキャフォールド後のチェックリスト
スキャフォールド後、ユーザーに次の作業を案内してください。
- ✅
package.jsonのメタデータを確認してカスタマイズする - ✅ アプリケーションアイコンを追加する(すべてのプラットフォーム)
- ✅ コード署名証明書を設定する
- ✅ 自動更新用の GitHub リポジトリをセットアップする
- ✅ ホットリロードと開発ワークフローをテストする
- ✅ 対象のすべてのプラットフォーム向けにビルドする
- ✅ 更新メカニズムをテストする
- ✅ セキュリティ設定を確認する
- ✅ エラートラッキングを追加する(Sentry など)
- ✅ ユーザードキュメントを作成する
バージョン互換性
このスキルの対象:
- Electron:v28 以降(最新の安定版)
- Node.js:v18 以降の LTS
- TypeScript:v5 以降
- Electron Forge:v7 以降
- Electron Builder:v24 以降
破壊的変更については、常に最新の Electron ドキュメントを確認してください。