> ## Documentation Index
> Fetch the complete documentation index at: https://extension.js.org/llms.txt
> Use this file to discover all available pages before exploring further.

# 面向 Chrome 与 Firefox 的跨浏览器扩展开发

> 在一个项目里把同一个扩展发布到 Chrome、Edge 和 Firefox。Extension.js 负责处理浏览器特定的 manifest 字段，并为每个目标生成构建产物。

<AvatarBrowsers browsers={["chrome", "firefox", "edge"]} />

Extension.js 在开发与构建期间处理浏览器特定的设置。你可以从同一个项目为 Chromium 与 Gecko(Firefox 引擎) 目标生成运行时正确的产物。

## 跨浏览器扩展开发

跨浏览器扩展开发意味着写一个扩展同时发布到 Chrome、Edge 和 Firefox，而无需 fork 代码。Extension.js 会把同一个项目编译成各浏览器对应的产物(`dist/chrome`、`dist/edge`、`dist/firefox`)，并按当前目标过滤 manifest。重载循环、运行时 API 和打包流程都与你当前调试的浏览器保持一致。

使用一份 `manifest.json` 即可针对特定浏览器或自定义二进制文件。如果你需要在 Chromium 系目标里使用 `browser.*` API 兼容性，可以启用 polyfill。

## Chrome 与 Firefox 扩展兼容性

Chrome 与 Firefox 扩展在大部分 WebExtensions 接口上是一致的，但有三处日常都会遇到的差异：

* **后台脚本：** Chrome (Manifest V3) 要求 `background.service_worker`。Firefox 使用 `background.scripts`，并采用非持久事件页。Extension.js 通过同一份带前缀的 manifest 同时分发到两者。
* **运行时 API 命名空间：** Firefox 原生支持 `browser.*`。Chromium 使用 `chrome.*`。在 Chromium 目标中传入 `--polyfill` 可以填平这个差异。
* **权限与内容安全策略 (CSP)：** 浏览器对部分 `permissions` 和 `host_permissions` 条目的处理不同。把浏览器差异放进带前缀的 manifest 键里，而不是在运行时做特性检测。

## 浏览器特定的 manifest 字段

浏览器特定的 manifest 字段是 Extension.js 让一份 `manifest.json` 在多浏览器中工作的方式。编译时 Extension.js 会按当前目标过滤带前缀的键(`chromium:`、`chrome:`、`edge:`、`firefox:`、`gecko:`)。不带前缀的键在所有目标中都生效。完整前缀列表请参见[浏览器特定的 manifest 字段](/docs/features/browser-specific-fields)。

## 模板示例

### `action`

<img src="https://mintcdn.com/extensionjs/VCnDd7fX2Nza24SE/images/examples/action/screenshot.png?fit=max&auto=format&n=VCnDd7fX2Nza24SE&q=85&s=5e4f6a24e0d133524a58b78e0a1d7585" alt="action template screenshot" width="2400" height="1800" data-path="images/examples/action/screenshot.png" />

通过一个能在 Chrome、Firefox 和 Edge 中运行的 action 弹窗，体验跨浏览器兼容性。

<CodeGroup>
  ```bash npm theme={null}
  npx extension@latest create my-extension --template=action
  ```

  ```bash pnpm theme={null}
  pnpx extension@latest create my-extension --template=action
  ```

  ```bash yarn theme={null}
  yarn dlx extension@latest create my-extension --template=action
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=action
  ```

  ```bash bun theme={null}
  bunx extension@latest create my-extension --template=action
  ```
</CodeGroup>

代码仓库：[extension-js/examples/action](https://github.com/extension-js/examples/tree/main/examples/action)

## 工作原理

### 1) 选择浏览器目标

选择你想运行扩展的位置。

用 `--browser` 选择常见目标，或传入自定义的浏览器二进制路径。

<CodeGroup>
  ```bash npm theme={null}
  extension dev --browser firefox
  ```

  ```bash pnpm theme={null}
  extension dev --browser firefox
  ```

  ```bash yarn theme={null}
  extension dev --browser firefox
  ```

  ```bash bun theme={null}
  extension dev --browser firefox
  ```

  ```bash bun theme={null}
  extension dev --browser firefox
  ```
</CodeGroup>

<CodeGroup>
  ```bash npm theme={null}
  extension dev --chromium-binary /Applications/Brave\\ Browser.app/Contents/MacOS/Brave\\ Browser
  ```

  ```bash pnpm theme={null}
  extension dev --chromium-binary /Applications/Brave\\ Browser.app/Contents/MacOS/Brave\\ Browser
  ```

  ```bash yarn theme={null}
  extension dev --chromium-binary /Applications/Brave\\ Browser.app/Contents/MacOS/Brave\\ Browser
  ```

  ```bash bun theme={null}
  extension dev --chromium-binary /Applications/Brave\\ Browser.app/Contents/MacOS/Brave\\ Browser
  ```

  ```bash bun theme={null}
  extension dev --chromium-binary /Applications/Brave\\ Browser.app/Contents/MacOS/Brave\\ Browser
  ```
</CodeGroup>

使用与你的操作系统匹配的二进制路径：

* **macOS**：`/Applications/Brave Browser.app/Contents/MacOS/Brave Browser`
* **Linux**：`/usr/bin/brave-browser`(或其他基于 Chromium 的浏览器二进制)
* **Windows**：`"C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"`

当你传入二进制路径时，Extension.js 会把它映射到对应的浏览器引擎目标：

* `--chromium-binary` 对应 `chromium-based`
* `--gecko-binary` 对应 `gecko-based`

### 2) 按浏览器过滤 manifest 字段并编译

编译期间，Extension.js 只包含当前所选浏览器对应的 manifest 字段。

例如：

```json theme={null}
{
  "chromium:background": {
    "service_worker": "sw.js"
  },
  "firefox:background": {
    "scripts": ["sw.js"]
  }
}
```

对于 Chromium 系目标，Extension.js 使用 `chromium:`、`chrome:`、`edge:` 等前缀。\
对于 Firefox 系目标，则使用 `firefox:` 和 `gecko:`。

<Note>
  完整的带前缀 manifest 字段说明，请参见[浏览器特定的 manifest 字段](/docs/features/browser-specific-fields)。
</Note>

### 3) 按浏览器目标输出

Extension.js 会把每个目标写入各自的构建目录：

* `dist/chrome`
* `dist/edge`
* `dist/firefox`
* `dist/chromium-based`(自定义 Chromium 引擎)
* `dist/gecko-based`(自定义 Gecko 引擎)

这样你的构建产物井井有条，也更便于在 CI 中发布。

### 4) 可选：为 Chromium 目标启用 `browser.*` polyfill

如果你的代码使用 `browser.*`，可以在 Chromium 系目标中启用 `--polyfill`：

<CodeGroup>
  ```bash npm theme={null}
  extension build --browser chrome --polyfill
  ```

  ```bash pnpm theme={null}
  extension build --browser chrome --polyfill
  ```

  ```bash yarn theme={null}
  extension build --browser chrome --polyfill
  ```

  ```bash bun theme={null}
  extension build --browser chrome --polyfill
  ```

  ```bash bun theme={null}
  extension build --browser chrome --polyfill
  ```
</CodeGroup>

启用后，Extension.js 会为非 Firefox 目标使用 `webextension-polyfill`(Mozilla 的 `browser.*` 兼容库)。\
对于 Firefox，Extension.js 会跳过这一步，因为 Firefox 已原生支持 `browser.*`。

## 最佳实践

* **保持一份代码**：尽量用带前缀的 manifest 字段表达浏览器差异。
* **每次只构建一个目标**：在持续集成 (CI) 中为每个浏览器单独生成产物(`dist/<browser>`)。
* **必要时再用 `--polyfill`**：仅当 Chromium 系目标依赖 `browser.*` 时启用。
* **及早检查 API 支持情况**：依赖浏览器特定 API 前先查阅 [MDN WebExtensions 文档](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions)。

## 下一步

* 进一步了解[可用浏览器](/docs/browsers/browsers-available)。
* 进一步了解[浏览器特定的 manifest 字段](/docs/features/browser-specific-fields)。
