mcpField
E
electrobun-best-practices

electrobun-best-practices

github.com/alleneubank開発50317 回インストール18 週間前に更新
リポジトリ

electrobun-best-practices について

Electrobun Best Practicesは、TypeScriptとBunでクロスプラットフォームのデスクトップアプリを構築するためのガイダンススキルです。安全な既定値、型付きRPC、ビルド・更新・配布の運用方法を扱います。

主な機能

  1. 01Bunとブラウザーコンテキストの構成案内
  2. 02共有型付きRPCパターンの定義
  3. 03サンドボックスとナビゲーション規則の適用
  4. 04終了処理とアプリイベントへの対応
  5. 05ビルド・更新・セッションの問題調査

活用シーン

  1. 01Electrobunアプリの構成を整備
  2. 02型付きRPCでBunとブラウザーを接続
  3. 03信頼できないコンテンツやユーザーセッションを分離
  4. 04アップデーターやビルドフックの問題を診断

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alleneubank/claude-code --skill electrobun-best-practices

インストール後、Claude Code で/electrobun-best-practicesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
build-config.md
platform-apis.md
window-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 とブラウザーの両方のハンドラーと一致していることを確認します。
  • 正規の URL へのナビゲーションがブロックされる:
    • setNavigationRules の順序を確認します。最後に一致したルールが適用されます。
    • 厳格な許可リストモードを意図的に使用する場合に限り、^* を先頭に置いてください。
  • アップデーターが更新なしと表示する:
    • release.baseUrl と、アップロードした artifacts/ の命名規則({channel}-{os}-{arch}-...)を確認します。
    • チャネルとビルド環境が一致していることを確認します(canary と stable)。
  • ユーザーセッションがアカウント間で漏れる:
    • アカウントごとに明示的なパーティションを使用し、Session.fromPartition(...) で Cookie を管理します。
  • ビルドフックが実行されない:
    • フックのパスが正しく、Bun で実行可能であることを確認します。
    • フックの環境変数(たとえば ELECTROBUN_BUILD_ENV、ELECTROBUN_OS、ELECTROBUN_ARCH)を確認します。

リファレンスファイル

コメント