electrobun-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Electrobun Best Practices

Electrobun 最佳实践

Electrobun builds cross-platform desktop apps with TypeScript and Bun. This skill gives safe defaults, typed RPC patterns, and operational guidance for build/update/distribution.
Electrobun 使用 TypeScript 和 Bun 构建跨平台桌面应用。此 skill 提供安全默认配置、类型化 RPC 模式,以及构建、更新和分发方面的运维指导。

Pair with TypeScript Best Practices

配合 TypeScript 最佳实践使用

Always load
typescript-best-practices
alongside this skill.
始终将
typescript-best-practices
与此 skill 一同加载。

Version and Freshness

版本与时效性

Electrobun APIs evolve quickly. Before relying on advanced options or platform-specific behavior, verify against current docs and CLI output.
Electrobun API 演进迅速。在依赖高级选项或平台特定行为之前,请根据最新文档和 CLI 输出进行验证。

Architecture

架构

Electrobun apps run as Bun apps:
  • Bun process (main): imports from
    electrobun/bun
  • Browser context (views): imports from
    electrobun/view
  • Shared types: RPC schemas shared between both contexts
IPC between bun and browser contexts uses postMessage, FFI, and (in some paths) encrypted WebSockets.
Electrobun 应用以 Bun 应用的形式运行:
  • Bun 进程(主进程):从
    electrobun/bun
    导入
  • 浏览器上下文(视图):从
    electrobun/view
    导入
  • 共享类型:两个上下文共享的 RPC schema
Bun 与浏览器上下文之间的 IPC 使用 postMessage、FFI,以及(在某些路径中)加密的 WebSocket。

Quick Start

快速开始

bash
bunx electrobun init
bun install
bun start
Recommended scripts:
json
{
  "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"
  }
}
bash
bunx electrobun init
bun install
bun start
推荐脚本:
json
{
  "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"
  }
}

Secure Defaults

安全默认值

Use this baseline for untrusted or third-party content:
typescript
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);
});
Security checklist:
  • Use
    sandbox: true
    for untrusted content.
  • Apply strict navigation allowlists.
  • Use separate
    partition
    values for isolation.
  • Validate all
    host-message
    payloads from
    <electrobun-webview>
    preload scripts.
  • Do not write to
    PATHS.RESOURCES_FOLDER
    at runtime; use
    Utils.paths.userData
    .
面对不可信或第三方内容时,使用以下基线配置:
typescript
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>
    preload script 传递的所有
    host-message
    payload。
  • 不要在运行时写入
    PATHS.RESOURCES_FOLDER
    ;请使用
    Utils.paths.userData
    。

Typed RPC (Minimal Pattern)

类型化 RPC(最小模式)

typescript
// 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 };
    };
  }>;
};
typescript
// 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>" });
typescript
// 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" });
typescript
// 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 };
    };
  }>;
};
typescript
// 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>" });
typescript
// 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" });

Events and Shutdown

事件与关闭

Use
before-quit
for shutdown cleanup instead of relying on
process.on("exit")
for async work.
typescript
import Electrobun from "electrobun/bun";

Electrobun.events.on("before-quit", async (e) => {
  await saveState();
  // e.response = { allow: false }; // optional: cancel quit
});
Important caveat:
  • Linux currently has a caveat where some system-initiated quit paths (for example Ctrl+C/window-manager/taskbar quit) may not fire
    before-quit
    . Programmatic quit via
    Utils.quit()
    /
    process.exit()
    is reliable.
对于异步清理工作,使用
before-quit
处理关闭流程,不要依赖
process.on("exit")
。
typescript
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()
    进行程序化退出是可靠的。

Common Patterns

常见模式

  • Keyboard shortcuts (copy/paste/undo): define an Edit
    ApplicationMenu
    with role-based items.
  • Tray-only app: set
    runtime.exitOnLastWindowClosed: false
    , then drive UX from
    Tray
    .
  • Multi-account isolation: use separate
    partition
    values per account.
  • Chromium consistency: set
    bundleCEF: true
    and
    defaultRenderer: "cef"
    in platform config.
  • 键盘快捷键(复制、粘贴、撤销):定义一个 Edit 类型的
    ApplicationMenu
    ,其中包含基于 role 的菜单项。
  • 仅驻留托盘的应用:将
    runtime.exitOnLastWindowClosed: false
    ,然后通过
    Tray
    驱动用户体验。
  • 多账户隔离:为每个账户使用不同的
    partition
    值。
  • Chromium 一致性:在平台配置中设置
    bundleCEF: true
    和
    defaultRenderer: "cef"
    。

Troubleshooting

故障排除

  • RPC calls fail unexpectedly:
    • Check whether the target webview is sandboxed (
      sandbox: true
      disables RPC).
    • Confirm shared RPC types match both bun and browser handlers.
  • Navigation blocks legitimate URLs:
    • Review
      setNavigationRules
      ordering; last match wins.
    • Keep
      ^*
      first only when you intentionally run strict allowlist mode.
  • Updater says no update:
    • Verify
      release.baseUrl
      and uploaded
      artifacts/
      naming (
      {channel}-{os}-{arch}-...
      ).
    • Confirm channel/build env alignment (
      canary
      vs
      stable
      ).
  • User sessions leak across accounts:
    • Use explicit per-account partitions and manage cookies via
      Session.fromPartition(...)
      .
  • Build hooks not running:
    • Ensure hook paths are correct and executable via Bun.
    • Inspect hook env vars (for example
      ELECTROBUN_BUILD_ENV
      ,
      ELECTROBUN_OS
      ,
      ELECTROBUN_ARCH
      ).
  • RPC 调用意外失败:
    • 检查目标 webview 是否已启用沙箱(
      sandbox: true
      会禁用 RPC)。
    • 确认共享的 RPC 类型与 Bun 和浏览器两侧的 handler 均匹配。
  • 合法 URL 被阻止:
    • 检查
      setNavigationRules
      的顺序;最后一个匹配项生效。
    • 仅当有意启用严格允许列表模式时,才将
      ^*
      放在首位。
  • 更新器提示没有更新:
    • 验证
      release.baseUrl
      以及已上传的
      artifacts/
      命名(
      {channel}-{os}-{arch}-...
      )。
    • 确认 channel 与构建环境一致(
      canary
      与
      stable
      )。
  • 用户会话在不同账户之间泄漏:
    • 为每个账户使用明确独立的 partition,并通过
      Session.fromPartition(...)
      管理 cookie。
  • 构建 hook 未运行:
    • 确保 hook 路径正确,并可通过 Bun 执行。
    • 检查 hook 环境变量(例如
      ELECTROBUN_BUILD_ENV
      、
      ELECTROBUN_OS
      、
      ELECTROBUN_ARCH
      )。

Reference Files

参考文件

  • Build config, artifacts, and hooks: reference/build-config.md
  • BrowserWindow, BrowserView, and webview tag APIs: reference/window-and-webview.md
  • Menus, tray, events, updater, utils/session APIs: reference/platform-apis.md
  • 构建配置、制品和 hook:reference/build-config.md
  • BrowserWindow、BrowserView 和 webview 标签 API:reference/window-and-webview.md
  • 菜单、托盘、事件、更新器、utils/session API:reference/platform-apis.md