> ## 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.

# 浏览器扩展的 Manifest V3 排错

> 修复 Chrome 和 Firefox 中 Manifest V3 的常见问题：service worker、web_accessible_resources、host_permissions 以及按浏览器的行为差异。

Manifest V3（MV3）用 service worker 取代了背景页，收紧了内容安全策略，并重塑了扩展声明网络和宿主访问的方式。大多数日常痛点都有同一个根因：MV3 假设背景代码是短暂的、事件驱动的。Chrome 和 Firefox 对少数几个键的解释也有所不同。

本页汇总了构建 MV3 扩展时最常出现的问题，给出精确修复方案以及 Extension.js 会替你处理的部分。

## Manifest V3 中带 `type: "module"` 的背景 `service_worker`

Chromium 在 MV3 背景中使用 service worker。要从中导入 ES 模块，manifest 需要 `type: "module"`：

```json theme={null}
{
  "manifest_version": 3,
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  }
}
```

如果没有 `"type": "module"`，`import` 语句会在注册时失败，并且扩展控制台里看不到清晰的报错。加上之后，你就可以在 worker 文件里使用现代 ES 模块语法。

当你的背景入口使用 ES 模块语法时，Extension.js 会自动设置 `type: "module"`。它还会把 `.ts`/`.tsx` worker 编译成单个打包产物，让模块解析在生产环境中仍然可用。

## 为什么 `background.js` 在 Manifest V3 中表现不同

在 Manifest V2 中，`background.js` 运行在一个持久的、带 DOM 的背景页里。在 Chromium 的 Manifest V3 中，背景作为 service worker 运行：

* 没有 DOM。`window`、`document`、`XMLHttpRequest` 和 `localStorage` 都没有了。请使用 `fetch` 和 `chrome.storage`。
* worker 在空闲时 **可能随时被终止**，并在下一个事件到来时被唤醒。不要把状态存在模块作用域变量中；用 `chrome.storage` 持久化。
* 允许顶层 `await`，但长时间的初始化本身不会让 worker 一直存活。
* 在文件顶部 **同步地** 注册事件监听器，不要在异步回调内部注册。在异步回调内部注册的监听器，对于唤醒并加载这个 worker 的那个事件不会触发。

Firefox 仍然使用非持久事件页，而不是 service worker。Extension.js 会从同一份源代码把 Chromium 路由到 `service_worker`，把 Firefox 路由到 `scripts`，从而让同一个背景入口为每个目标正确编译。

## Manifest V3 中的 `web_accessible_resources`

Manifest V3 把 `web_accessible_resources` 从一个扁平的文件数组改为 `{ resources, matches }` 块的列表：

```json theme={null}
{
  "web_accessible_resources": [
    {
      "resources": ["images/logo.png", "pages/injected.html"],
      "matches": ["https://example.com/*"]
    }
  ]
}
```

常见错误：

* 列出了一个不在构建产物中的路径。Extension.js 只输出被 `manifest.json`、入口 HTML 或导入代码引用的文件。请把文件作为资源添加进去，它才会落到 `dist/<browser>`。
* 忘了 `matches`。没有它，资源不会暴露给任何源。
* 使用 V2 风格的扁平字符串。浏览器在 MV3 中会默默忽略它们。

完整模式见 [`web_accessible_resources` 实现](/docs/implementation-guide/web-accessible-resources)，其中包含把一个扩展 URL 注入 content script 的做法。

## `host_permissions` 与 `permissions`

Manifest V3 把宿主访问从 `permissions` 数组中拆了出来：

| 键                                                    | 控制内容                                                          |
| ---------------------------------------------------- | ------------------------------------------------------------- |
| `permissions`                                        | 命名 API 接口（`storage`、`tabs`、`cookies`、`scripting`、`alarms` 等）。 |
| `host_permissions`                                   | 扩展可以读取或修改的 URL 匹配模式（`https://*/*`、`*://api.example.com/*`）。   |
| `optional_permissions` 与 `optional_host_permissions` | 在运行时通过 `chrome.permissions.request` 请求的权限。                    |

混淆它们的常见症状：

* `chrome.cookies.get` 在你有访问权限的站点上返回空：该 URL 需要 `host_permissions`，不只是 `cookies`。
* `chrome.scripting.executeScript` 报错 "Cannot access contents of url"：把该 URL 加入 `host_permissions`。
* Web Store 向用户警告"全站访问"，而你其实只需要一个源：把宿主模式收窄。

按 API 的参考见 [权限与宿主权限](/docs/implementation-guide/permissions-and-host-permissions)。

## Firefox 中的 `declarative_net_request`

`declarative_net_request`（DNR）是 MV3 中用于替代阻断式 `webRequest` 的方案。Firefox 支持它，但有几条限制：

* 静态规则资源文件（`rule_resources`）必须是合法的 JSON 数组。相比 Chrome，Firefox 对空文件或格式不正确的规则文件更严格。
* Chrome 支持的一些规则动作和条件在 Firefox 中仍是部分支持。请查阅 [MDN 的 `declarativeNetRequest` 参考](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/declarativeNetRequest) 了解当前的兼容矩阵。
* 要让 DNR 规则在跨源请求上生效，需要 `host_permissions`（或 `<all_urls>`）。

Extension.js 在构建时校验 DNR 资源，并按浏览器输出产物，让某个 Firefox 专属的规则文件不会落到 Chrome 构建里。

## Content script、worker 与扩展 URL

MV3 容易绊倒人的三个地方：

* **Content script 无法访问页面的 JavaScript 作用域。** 它们共享 DOM，而不是 window。请使用 `window.postMessage`（或一个指向 `web_accessible_resources` 条目的 `<script>` 标签）来与页面代码通信。
* **Service worker 在安装期间无法可靠地访问 `chrome.runtime.getURL`。** 请在需要它的事件处理器内部惰性地解析 URL。
* **扩展 URL 是按源限定的。** 你的扩展中的两个页面可以互相通信，但页面无法 fetch 它们，除非它们被列在 `web_accessible_resources` 中。

## Extension.js 在 Manifest V3 中如何帮你

* 自动把背景入口路由到 `service_worker`（Chromium）或 `scripts`（Firefox）。
* 当背景使用 ES 模块语法时，自动设置 `type: "module"`。
* 在构建时根据当前 manifest 版本校验 `web_accessible_resources`、`permissions` 和 `host_permissions`。
* 按浏览器输出 `dist/<browser>` 产物，让 Chrome 和 Firefox 之间的 MV3 差异彼此隔离。
* 在 `extension dev` 期间，保存即重载 content script、service worker 和 HTML 页面。

## 下一步

* 阅读 [权限与宿主权限](/docs/implementation-guide/permissions-and-host-permissions)。
* 阅读 [背景脚本](/docs/implementation-guide/background) 与 [Content scripts](/docs/implementation-guide/content-scripts)。
* 阅读 [`web_accessible_resources`](/docs/implementation-guide/web-accessible-resources)。
* 查看 [跨浏览器兼容性](/docs/features/cross-browser-compatibility) 了解构建流水线。
* 查看 [按浏览器的 manifest 字段](/docs/features/browser-specific-fields) 了解前缀化的 manifest 键。
* 看看每个 [浏览器扩展框架](/docs/compare) 如何处理 MV3 的差异。
