electrobun-platform

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Electrobun Cross-Platform Reference

Electrobun 跨平台参考

Platform Support Matrix

平台支持矩阵

PlatformOS valueArchStatusDefault Webview
macOS ARM64
macos
arm64
StableWKWebView
macOS Intel
macos
x64
StableWKWebView
Windows x64
win
x64
StableWebView2 (Edge)
Windows ARM64
win
arm64
Via emulationRuns x64 binary
Linux x64
linux
x64
StableGTKWebKit
Linux ARM64
linux
arm64
StableGTKWebKit
Build each platform on its native OS — no cross-compilation.
平台OS 值架构状态默认 Webview
macOS ARM64
macos
arm64
稳定WKWebView
macOS Intel
macos
x64
稳定WKWebView
Windows x64
win
x64
稳定WebView2 (Edge)
Windows ARM64
win
arm64
通过模拟运行 x64 二进制文件
Linux x64
linux
x64
稳定GTKWebKit
Linux ARM64
linux
arm64
稳定GTKWebKit
每个平台都应在其原生 OS 上构建——不支持交叉编译。

Linux — Always Bundle CEF

Linux — 始终捆绑 CEF

GTKWebKit has severe limitations:
  • No webview layering (no overlapping webviews)
  • No masking
  • No
    <electrobun-webview>
    compositing
  • Renderer mixing not supported — all webviews must use same renderer
For anything beyond a single-webview app on Linux:
typescript
// electrobun.config.ts
build: {
  linux: { bundleCEF: true, defaultRenderer: 'cef' },
}
GTKWebKit 存在严重限制:
  • 不支持 Webview 分层(无法重叠 Webview)
  • 不支持蒙版
  • 不支持
    <electrobun-webview>
    合成
  • 不支持混用 Renderer——所有 Webview 必须使用同一个 Renderer
对于 Linux 上单 Webview 应用之外的任何场景:
typescript
// electrobun.config.ts
build: {
  linux: { bundleCEF: true, defaultRenderer: 'cef' },
}

Windows — Console Output

Windows — 控制台输出

Production Windows builds use the GUI subsystem — no console for end users.
cmd
set ELECTROBUN_CONSOLE=1
.\MyApp.exe
Has no effect on macOS or Linux. Dev builds auto-attach a console.
生产环境中的 Windows 构建使用 GUI 子系统——最终用户不会看到控制台。
cmd
set ELECTROBUN_CONSOLE=1
.\MyApp.exe
对 macOS 或 Linux 无效。开发构建会自动附加控制台。

Webview Hidden/Passthrough Behavior

Webview 隐藏/穿透行为

typescript
// macOS: hidden and passthrough are INDEPENDENT
webviewSetHidden(webviewId, true);       // hidden, still intercepts clicks
webviewSetPassthrough(webviewId, true);  // separate call for click-through

// Windows & Linux: hidden = hidden + passthrough automatically
webviewSetHidden(webviewId, true);       // hidden AND clicks pass through
// webviewSetPassthrough() is a no-op on Windows/Linux
typescript
// macOS: hidden and passthrough are INDEPENDENT
webviewSetHidden(webviewId, true);       // hidden, still intercepts clicks
webviewSetPassthrough(webviewId, true);  // separate call for click-through

// Windows & Linux: hidden = hidden + passthrough automatically
webviewSetHidden(webviewId, true);       // hidden AND clicks pass through
// webviewSetPassthrough() is a no-op on Windows/Linux

<electrobun-webview>
HTML Tag (OOPIF)

<electrobun-webview>
HTML 标签(OOPIF)

Process-isolated "super iframes" — positioned by DOM, rendered natively. Requires CEF on Linux.
html
<electrobun-webview
  src="https://example.com"
  width="100%"
  height="400px"
  renderer="cef">
</electrobun-webview>
Access from bun:
BrowserView.getAll()
includes OOPIFs.
进程隔离的“super iframes”——由 DOM 定位,以原生方式渲染。
Linux 上需要 CEF。
html
<electrobun-webview
  src="https://example.com"
  width="100%"
  height="400px"
  renderer="cef">
</electrobun-webview>
从 bun 访问时:
BrowserView.getAll()
包含 OOPIF。

CEF Version Override

CEF 版本覆盖

typescript
build: {
  cefVersion: '144.0.11+ge135be2+chromium-144.0.7559.97',
}
Same major = safe. Adjacent major = usually fine. Distant majors = higher risk.
typescript
build: {
  cefVersion: '144.0.11+ge135be2+chromium-144.0.7559.97',
}
相同主版本号 = 安全。相邻主版本号 = 通常没问题。相距较远的主版本号 = 风险更高。

Chromium Flags (CEF only)

Chromium 标志(仅限 CEF)

typescript
build: {
  mac: {
    bundleCEF: true,
    chromiumFlags: {
      'show-paint-rects': true,
      'user-agent': 'MyApp/1.0',
      'disable-web-security': true,
    },
  },
}
typescript
build: {
  mac: {
    bundleCEF: true,
    chromiumFlags: {
      'show-paint-rects': true,
      'user-agent': 'MyApp/1.0',
      'disable-web-security': true,
    },
  },
}

Per-Window Renderer Override

逐窗口 Renderer 覆盖

typescript
// Override defaultRenderer per window
const win = new BrowserWindow({ url: '...', renderer: 'native' });
const cefWin = new BrowserWindow({ url: '...', renderer: 'cef' });
Mixing allowed on macOS and Windows. Not allowed on Linux.
typescript
// Override defaultRenderer per window
const win = new BrowserWindow({ url: '...', renderer: 'native' });
const cefWin = new BrowserWindow({ url: '...', renderer: 'cef' });
macOS 和 Windows 允许混用。Linux 不允许混用。

Events API

事件 API

typescript
import Electrobun from 'electrobun/bun';

// App lifecycle
Electrobun.events.on('before-quit', (e) => {
  if (hasUnsavedChanges()) e.response = { allow: false }; // cancel quit
});
Electrobun.events.on('open-url', (e) => {
  const url = new URL(e.data.url); // macOS URL scheme deep links
});

// Window events (global — all windows)
Electrobun.events.on('close', (e) => { /* e.data.id */ });
Electrobun.events.on('resize', (e) => { /* e.data.id, width, height */ });
Electrobun.events.on('move', (e) => { /* e.data.id, x, y */ });
Electrobun.events.on('blur', (e) => { /* e.data.id */ });
Electrobun.events.on('focus', (e) => { /* e.data.id */ });

// Menu / tray
Electrobun.events.on('application-menu-clicked', (e) => { /* e.data.action */ });
Electrobun.events.on('context-menu-clicked', (e) => { /* e.data.action, data */ });
Electrobun.events.on('tray-menu-clicked', (e) => { /* e.data.action */ });
Quit trigger sources: dock icon, Cmd+Q, Ctrl+C, SIGTERM, window close,
Utils.quit()
,
process.exit()
— all route through
before-quit
.
Linux caveat: system-initiated quit paths (window-manager close, taskbar) may bypass
before-quit
.
Utils.quit()
and
process.exit()
are reliable.
typescript
import Electrobun from 'electrobun/bun';

// App lifecycle
Electrobun.events.on('before-quit', (e) => {
  if (hasUnsavedChanges()) e.response = { allow: false }; // cancel quit
});
Electrobun.events.on('open-url', (e) => {
  const url = new URL(e.data.url); // macOS URL scheme deep links
});

// Window events (global — all windows)
Electrobun.events.on('close', (e) => { /* e.data.id */ });
Electrobun.events.on('resize', (e) => { /* e.data.id, width, height */ });
Electrobun.events.on('move', (e) => { /* e.data.id, x, y */ });
Electrobun.events.on('blur', (e) => { /* e.data.id */ });
Electrobun.events.on('focus', (e) => { /* e.data.id */ });

// Menu / tray
Electrobun.events.on('application-menu-clicked', (e) => { /* e.data.action */ });
Electrobun.events.on('context-menu-clicked', (e) => { /* e.data.action, data */ });
Electrobun.events.on('tray-menu-clicked', (e) => { /* e.data.action */ });
退出触发来源:Dock 图标、Cmd+Q、Ctrl+C、SIGTERM、窗口关闭、
Utils.quit()
、
process.exit()
——所有路径都会进入
before-quit
。
Linux 注意事项:由系统触发的退出路径(窗口管理器关闭、任务栏)可能会绕过
before-quit
。
Utils.quit()
和
process.exit()
可靠有效。

URL Schemes / Deep Linking

URL Schemes / 深层链接

macOS only. App must be in
/Applications
or
~/Applications
.
typescript
// electrobun.config.ts
app: { urlSchemes: ['myapp', 'myapp-dev'] }

// src/bun/index.ts
Electrobun.events.on('open-url', (e) => {
  const url = new URL(e.data.url);
  if (url.pathname.startsWith('/auth')) { /* handle */ }
});
Windows/Linux URL schemes not yet supported.
仅支持 macOS。应用必须位于
/Applications
或
~/Applications
。
typescript
// electrobun.config.ts
app: { urlSchemes: ['myapp', 'myapp-dev'] }

// src/bun/index.ts
Electrobun.events.on('open-url', (e) => {
  const url = new URL(e.data.url);
  if (url.pathname.startsWith('/auth')) { /* handle */ }
});
Windows/Linux 尚不支持 URL Schemes。

Security Checklist

安全检查清单

  • sandbox: true
    on any BrowserView loading untrusted URLs — disables RPC, events still work
  • setNavigationRules
    to allowlist permitted navigation targets; last match wins
  • Never expose
    electrobun/bun
    APIs to sandboxed views — route through RPC with validation
  • Use separate
    partition
    values per account for session isolation
  • Prefer
    views://
    over
    file://
    for local assets
  • 对任何加载不受信任 URL 的 BrowserView 设置
    sandbox: true
    ——这会禁用 RPC,但事件仍可正常工作
  • 使用
    setNavigationRules
    将允许的导航目标加入白名单;最后一次匹配优先
  • 切勿向沙箱化视图暴露
    electrobun/bun
    API——应通过带验证的 RPC 进行路由
  • 为每个账户使用不同的
    partition
    值,以隔离会话
  • 对于本地资源,优先使用
    views://
    而非
    file://

Code Signing (macOS)

代码签名(macOS)

One-Time Setup

一次性设置

  1. Install full Xcode from App Store (not CLI tools alone — avoids expired cert issues)
  2. Xcode → Settings → Accounts → add Apple ID → Manage Certificates →
    +
    → Developer ID Application
  3. Apple Developer Portal: Identifiers → register bundle ID
  4. account.apple.com: App Specific Passwords → create one
  1. 从 App Store 安装完整的 Xcode(不能只安装 CLI 工具——可避免证书过期问题)
  2. Xcode → Settings → Accounts → 添加 Apple ID → Manage Certificates →
    +
    → Developer ID Application
  3. Apple Developer Portal:Identifiers → 注册 bundle ID
  4. account.apple.com:App Specific Passwords → 创建一个

Required Env Vars

必需环境变量

bash
export ELECTROBUN_DEVELOPER_ID="My Corp Inc. (BGU899NB8T)"
export ELECTROBUN_TEAMID="BGU899NB8T"
export ELECTROBUN_APPLEID="you@example.com"
export ELECTROBUN_APPLEIDPASS="xxxx-xxxx-xxxx-xxxx"
Unsigned apps show "damaged and can't be opened" — users fix with:
bash
xattr -cr /Applications/YourApp.app
bash
export ELECTROBUN_DEVELOPER_ID="My Corp Inc. (BGU899NB8T)"
export ELECTROBUN_TEAMID="BGU899NB8T"
export ELECTROBUN_APPLEID="you@example.com"
export ELECTROBUN_APPLEIDPASS="xxxx-xxxx-xxxx-xxxx"
未签名的应用会显示“已损坏且无法打开”——用户可以使用以下命令修复:
bash
xattr -cr /Applications/YourApp.app

Entitlements

Entitlements(权限声明)

typescript
build: {
  mac: {
    entitlements: {
      'com.apple.security.device.camera': 'Needed for video',
      'com.apple.security.device.microphone': 'Needed for audio',
    }
  }
}
typescript
build: {
  mac: {
    entitlements: {
      'com.apple.security.device.camera': 'Needed for video',
      'com.apple.security.device.microphone': 'Needed for audio',
    }
  }
}

Application Icons

应用程序图标

typescript
build: {
  mac: { icons: 'icon.iconset' },
  // icon.iconset/ must contain icon_{16,32,64,128,256,512}x{same}[@2x].png
  win: { icon: 'icon.iconset/icon_256x256.png' }, // .ico or .png, auto-converted
  linux: { icon: 'icon.iconset/icon_256x256.png' }, // 256x256+ .png
}
Reuse PNGs from the macOS iconset for Windows/Linux — no separate files needed.
typescript
build: {
  mac: { icons: 'icon.iconset' },
  // icon.iconset/ must contain icon_{16,32,64,128,256,512}x{same}[@2x].png
  win: { icon: 'icon.iconset/icon_256x256.png' }, // .ico or .png, auto-converted
  linux: { icon: 'icon.iconset/icon_256x256.png' }, // 256x256+ .png
}
可复用 macOS iconset 中的 PNG 文件作为 Windows/Linux 图标——无需单独准备文件。

Artifact Naming Convention

制品命名规范

Artifacts use
{channel}-{os}-{arch}-
prefix. Stable omits the channel. App name spaces stripped.
canary-macos-arm64-MyApp-canary.dmg
canary-macos-arm64-MyApp-canary.app.tar.zst
canary-macos-arm64-{prevHash}.patch
canary-win-x64-MyApp-Setup-canary.zip
canary-win-x64-MyApp-canary.tar.zst
canary-linux-x64-MyAppSetup-canary.tar.gz
stable-macos-arm64-MyApp.dmg     ← no "stable" in name on stable channel
Keep old patches on your static host — users >1 version behind auto-fall back to full
.tar.zst
.
制品使用
{channel}-{os}-{arch}-
前缀。Stable 渠道会省略渠道名。应用名称中的空格会被移除。
canary-macos-arm64-MyApp-canary.dmg
canary-macos-arm64-MyApp-canary.app.tar.zst
canary-macos-arm64-{prevHash}.patch
canary-win-x64-MyApp-Setup-canary.zip
canary-win-x64-MyApp-canary.tar.zst
canary-linux-x64-MyAppSetup-canary.tar.gz
stable-macos-arm64-MyApp.dmg     ← no "stable" in name on stable channel
请在静态托管上保留旧补丁——落后超过 1 个版本的用户会自动回退到完整的
.tar.zst
文件。

Release Hosting

发布托管

Static file host — no server required: S3, Cloudflare R2, GCS, GitHub Releases.
typescript
release: {
  baseUrl: 'https://storage.googleapis.com/mybucket/myapp/',
  // GitHub Releases:
  // baseUrl: 'https://github.com/ORG/REPO/releases/latest/download',
}
GitHub Releases limitation:
/releases/latest/download
skips prereleases. Stable works; canary auto-updates will NOT — use R2/S3 for canary channel.
静态文件托管——无需服务器:S3、Cloudflare R2、GCS、GitHub Releases。
typescript
release: {
  baseUrl: 'https://storage.googleapis.com/mybucket/myapp/',
  // GitHub Releases:
  // baseUrl: 'https://github.com/ORG/REPO/releases/latest/download',
}
GitHub Releases 限制:
/releases/latest/download
会跳过预发布版本。Stable 渠道可用;但 Canary 自动更新将不可用——Canary 渠道请使用 R2/S3。

CI Build Matrix (GitHub Actions)

CI 构建矩阵(GitHub Actions)

Each platform must build on its own native runner:
yaml
jobs:
  build-macos-arm64:
    runs-on: macos-14          # Apple Silicon
  build-macos-x64:
    runs-on: macos-13          # Intel
  build-windows:
    runs-on: windows-latest
  build-linux:
    runs-on: ubuntu-latest
每个平台都必须在各自的原生 runner 上构建:
yaml
jobs:
  build-macos-arm64:
    runs-on: macos-14          # Apple Silicon
  build-macos-x64:
    runs-on: macos-13          # Intel
  build-windows:
    runs-on: windows-latest
  build-linux:
    runs-on: ubuntu-latest

Each job:

Each job:

uses: actions/checkout@v4

uses: actions/checkout@v4

uses: oven-sh/setup-bun@v2

uses: oven-sh/setup-bun@v2

run: bun install

run: bun install

run: electrobun build --env=stable

run: electrobun build --env=stable

uses: softprops/action-gh-release@v1

uses: softprops/action-gh-release@v1

with: files: artifacts/*

with: files: artifacts/*


Tag naming convention: tags containing `-canary` → canary build; all others → stable.

标签命名规范:包含 `-canary` 的标签 → Canary 构建;其他所有标签 → Stable。

ASAR Packaging

ASAR 打包

typescript
build: {
  useAsar: true,
  asarUnpack: ['*.node', '*.dll', '*.dylib', '*.so', 'data/large/**/*'],
}
Packs app resources into
app.asar
. Unpacked files →
app.asar.unpacked/
. Benefits: faster I/O, code obfuscation via randomized temp paths.
typescript
build: {
  useAsar: true,
  asarUnpack: ['*.node', '*.dll', '*.dylib', '*.so', 'data/large/**/*'],
}
将应用资源打包到
app.asar
中。解包后的文件 →
app.asar.unpacked/
。优点:I/O 更快;通过随机临时路径实现代码混淆。

Common Pitfalls

常见问题

IssueFix
Linux webview layering broken
bundleCEF: true
+
defaultRenderer: 'cef'
Canary auto-update not workingGitHub
/releases/latest
skips prereleases — use R2/S3
"damaged and can't be opened" macOSEnable
codesign + notarize
, or
xattr -cr
for testing
Code signing cert errorsInstall full Xcode from App Store, not just CLI tools
RPC type mismatch at runtimeConfirm shared type file is imported by both sides
Sandbox webview + RPC silent failure
sandbox: true
disables RPC — use events or remove sandbox
Windows no console outputSet
ELECTROBUN_CONSOLE=1
env var
URL schemes not registeringApp must be in
/Applications
, macOS only
Cross-compilation attemptEach platform must build on its own native OS
Linux renderer mixingAll webviews must use the same renderer on Linux
Old patches missingKeep all patch files on static host for sequential upgrades
before-quit
not firing on Linux
System-initiated quits may bypass it;
Utils.quit()
is reliable
Notarize + codesign disabled for speedTurn off during rapid debug cycles, re-enable for release
问题修复方法
Linux Webview 分层损坏
bundleCEF: true
+
defaultRenderer: 'cef'
Canary 自动更新不工作GitHub
/releases/latest
会跳过预发布版本——使用 R2/S3
macOS 显示“已损坏且无法打开”启用
codesign + notarize
,或在测试时使用
xattr -cr
代码签名证书错误从 App Store 安装完整 Xcode,而不只是 CLI 工具
运行时 RPC 类型不匹配确认共享类型文件已由两端导入
沙箱 Webview + RPC 静默失败
sandbox: true
会禁用 RPC——使用事件或移除沙箱
Windows 无控制台输出设置
ELECTROBUN_CONSOLE=1
环境变量
URL Schemes 无法注册应用必须位于
/Applications
,且仅支持 macOS
尝试交叉编译每个平台都必须在自己的原生 OS 上构建
Linux 上混用 Renderer所有 Webview 必须使用同一个 Renderer
缺少旧补丁在静态托管上保留所有补丁文件,以支持顺序升级
before-quit
在 Linux 上未触发
系统触发的退出会绕过它;
Utils.quit()
更可靠
为提高调试速度而禁用 Notarize + codesign在快速调试阶段将其关闭,发布前重新启用