Manifest V3 中带 type: "module" 的背景 service_worker
Chromium 在 MV3 背景中使用 service worker。要从中导入 ES 模块,manifest 需要 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 的那个事件不会触发。
service_worker,把 Firefox 路由到 scripts,从而让同一个背景入口为每个目标正确编译。
Manifest V3 中的 web_accessible_resources
Manifest V3 把 web_accessible_resources 从一个扁平的文件数组改为 { resources, matches } 块的列表:
- 列出了一个不在构建产物中的路径。Extension.js 只输出被
manifest.json、入口 HTML 或导入代码引用的文件。请把文件作为资源添加进去,它才会落到dist/<browser>。 - 忘了
matches。没有它,资源不会暴露给任何源。 - 使用 V2 风格的扁平字符串。浏览器在 MV3 中会默默忽略它们。
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 向用户警告”全站访问”,而你其实只需要一个源:把宿主模式收窄。
Firefox 中的 declarative_net_request
declarative_net_request(DNR)是 MV3 中用于替代阻断式 webRequest 的方案。Firefox 支持它,但有几条限制:
- 静态规则资源文件(
rule_resources)必须是合法的 JSON 数组。相比 Chrome,Firefox 对空文件或格式不正确的规则文件更严格。 - Chrome 支持的一些规则动作和条件在 Firefox 中仍是部分支持。请查阅 MDN 的
declarativeNetRequest参考 了解当前的兼容矩阵。 - 要让 DNR 规则在跨源请求上生效,需要
host_permissions(或<all_urls>)。
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 页面。
下一步
- 阅读 权限与宿主权限。
- 阅读 背景脚本 与 Content scripts。
- 阅读
web_accessible_resources。 - 查看 跨浏览器兼容性 了解构建流水线。
- 查看 按浏览器的 manifest 字段 了解前缀化的 manifest 键。
- 看看每个 浏览器扩展框架 如何处理 MV3 的差异。

