electrobun-best-practices について
Electrobun Best Practicesは、TypeScriptとBunでクロスプラットフォームのデスクトップアプリを構築するためのガイダンススキルです。安全な既定値、型付きRPC、ビルド・更新・配布の運用方法を扱います。
主な機能
- 01Bunとブラウザーコンテキストの構成案内
- 02共有型付きRPCパターンの定義
- 03サンドボックスとナビゲーション規則の適用
- 04終了処理とアプリイベントへの対応
- 05ビルド・更新・セッションの問題調査
活用シーン
- 01Electrobunアプリの構成を整備
- 02型付きRPCでBunとブラウザーを接続
- 03信頼できないコンテンツやユーザーセッションを分離
- 04アップデーターやビルドフックの問題を診断
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ alleneubank/ claude-code --skill electrobun-best-practicesインストール後、Claude Code で/electrobun-best-practicesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
reference/build-config.mdplatform-apis.mdwindow-and-webview.md詳細
Electrobun のベストプラクティス
Electrobun は TypeScript と Bun を使用して、クロスプラットフォームのデスクトップアプリを構築します。このスキルでは、安全なデフォルト設定、型付き RPC のパターン、ビルド/アップデート/配布に関する運用上のガイダンスを紹介します。
ドキュメント:https://blackboard.sh/electrobun/docs/
TypeScript のベストプラクティスと併用する
このスキルと併せて、必ず typescript-best-practices を読み込んでください。
バージョンと最新情報
Electrobun の API は急速に進化しています。高度なオプションやプラットフォーム固有の動作を利用する前に、最新のドキュメントと CLI の出力を確認してください。
アーキテクチャ
Electrobun アプリは Bun アプリとして動作します。
- Bun プロセス(メイン):
electrobun/bunからインポートします - ブラウザーコンテキスト(ビュー):
electrobun/viewからインポートします - 共有型:両方のコンテキストで共有される RPC スキーマ
Bun とブラウザーのコンテキスト間の IPC では、postMessage、FFI、および(一部の経路では)暗号化 WebSocket を使用します。
クイックスタート
bunx electrobun init
bun install
bun start
推奨スクリプト:
{
"scripts": {
"start": "electrobun run",
"dev": "electrobun dev",
"dev:watch": "electrobun dev --watch",
"build:dev": "bun install && electrobun build",
"build:canary": "electrobun build --env=canary",
"build:stable": "electrobun build --env=stable"
}
}
安全なデフォルト設定
信頼できないコンテンツやサードパーティーのコンテンツには、次の基本設定を使用してください。
import { BrowserWindow } from "electrobun/bun";
const win = new BrowserWindow({
title: "External Content",
url: "https://example.com",
sandbox: true, // disables RPC, events still work
partition: "persist:external",
});
win.webview.setNavigationRules([
"^*", // block everything by default
"*://example.com/*", // allow only trusted domain(s)
"^http://*", // enforce HTTPS
]);
win.webview.on("will-navigate", (e) => {
console.log("nav", e.data.url, "allowed", e.data.allowed);
});
セキュリティチェックリスト:
- 信頼できないコンテンツには
sandbox: trueを使用します。 - 厳格なナビゲーション許可リストを適用します。
- 分離のため、個別の
partition値を使用します。 <electrobun-webview>のプリロードスクリプトから送られるすべてのhost-messageペイロードを検証します。- 実行時に
PATHS.RESOURCES_FOLDERへ書き込まないでください。Utils.paths.userDataを使用してください。
型付き RPC(最小パターン)
// src/shared/types.ts
import type { RPCSchema } from "electrobun/bun";
export type MyRPC = {
bun: RPCSchema<{
requests: {
getUser: { params: { id: string }; response: { name: string } };
};
messages: {
logToBun: { msg: string };
};
}>;
webview: RPCSchema<{
requests: {
updateUI: { params: { html: string }; response: boolean };
};
messages: {
notify: { text: string };
};
}>;
};
// bun side
import { BrowserView, BrowserWindow } from "electrobun/bun";
import type { MyRPC } from "../shared/types";
const rpc = BrowserView.defineRPC<MyRPC>({
handlers: {
requests: {
getUser: ({ id }) => ({ name: `user-${id}` }),
},
messages: {
logToBun: ({ msg }) => console.log(msg),
},
},
});
const win = new BrowserWindow({
title: "App",
url: "views://mainview/index.html",
rpc,
});
await win.webview.rpc.updateUI({ html: "<p>Hello</p>" });
// browser side
import { Electroview } from "electrobun/view";
import type { MyRPC } from "../shared/types";
const rpc = Electroview.defineRPC<MyRPC>({
handlers: {
requests: {
updateUI: ({ html }) => {
document.body.innerHTML = html;
return true;
},
},
messages: {
notify: ({ text }) => console.log(text),
},
},
});
const electroview = new Electroview({ rpc });
await electroview.rpc.request.getUser({ id: "1" });
electroview.rpc.send.logToBun({ msg: "hello" });
イベントと終了処理
非同期処理のために process.on("exit") に依存せず、終了処理には before-quit を使用してください。
import Electrobun from "electrobun/bun";
Electrobun.events.on("before-quit", async (e) => {
await saveState();
// e.response = { allow: false }; // optional: cancel quit
});
重要な注意点:
- Linux では現在、システムによって開始される一部の終了経路(たとえば Ctrl+C/ウィンドウマネージャー/タスクバーからの終了)で
before-quitが発火しない場合があります。Utils.quit()/process.exit()によるプログラムからの終了は確実に動作します。
よくあるパターン
- キーボードショートカット(コピー/貼り付け/取り消し):ロールベースの項目を含む Edit
ApplicationMenuを定義します。 - トレイのみのアプリ:
runtime.exitOnLastWindowClosed: falseを設定し、Trayから UX を制御します。 - 複数アカウントの分離:アカウントごとに個別の
partition値を使用します。 - Chromium の一貫性:プラットフォーム設定で
bundleCEF: trueとdefaultRenderer: "cef"を設定します。
トラブルシューティング
- RPC 呼び出しが予期せず失敗する:
- 対象の webview がサンドボックス化されているか確認します(
sandbox: trueでは RPC が無効になります)。 - 共有 RPC 型が Bun とブラウザーの両方のハンドラーと一致していることを確認します。
- 対象の webview がサンドボックス化されているか確認します(
- 正規の URL へのナビゲーションがブロックされる:
setNavigationRulesの順序を確認します。最後に一致したルールが適用されます。- 厳格な許可リストモードを意図的に使用する場合に限り、
^*を先頭に置いてください。
- アップデーターが更新なしと表示する:
release.baseUrlと、アップロードしたartifacts/の命名規則({channel}-{os}-{arch}-...)を確認します。- チャネルとビルド環境が一致していることを確認します(
canaryとstable)。
- ユーザーセッションがアカウント間で漏れる:
- アカウントごとに明示的なパーティションを使用し、
Session.fromPartition(...)で Cookie を管理します。
- アカウントごとに明示的なパーティションを使用し、
- ビルドフックが実行されない:
- フックのパスが正しく、Bun で実行可能であることを確認します。
- フックの環境変数(たとえば
ELECTROBUN_BUILD_ENV、ELECTROBUN_OS、ELECTROBUN_ARCH)を確認します。
リファレンスファイル
- ビルド設定、アーティファクト、フック:reference/build-config.md
- BrowserWindow、BrowserView、webview タグ API:reference/window-and-webview.md
- メニュー、トレイ、イベント、アップデーター、utils/session API:reference/platform-apis.md