1.1 目的
MV3 改变了扩展程序保持存活和获取特权访问的方式。 如果您像 MV2 那样设计(持久后台 + 隐式状态),将更容易出现不稳定的行为。
实际上,MV3 关于约束:
-
后台是 事件驱动 的(通过扩展服务工作者(SW)实现;可能在空闲时被关闭)
-
权限必须是 明确和可解释的
-
请求修改向 声明性规则 (DNR)转移
1.2 使用时机 / 避免使用时机
使用本章节时:
-
你在迁移 MV2 代码,且遇到"随机停止工作"的问题
-
你正在设计一个新的 MV3 扩展,并希望获得正确的架构
避免使用时: 你只需要一个单独的 API 片段。 跳转至 API 章节。
1.3 一页面内的 MV3 运行时模型
用 上下文 思考(每个上下文有不同的能力):
-
服务工作者(SW)
-
事件处理器 + 协调
-
可能被停止/重启
-
没有 DOM (没有直接的页面访问)
-
扩展页(UI)
-
弹出窗口、选项页面、侧边栏面板
-
DOM 可用
-
生命周期取决于表面积(弹出窗口关闭得很快)
-
内容脚本
-
在网页中运行(隔离的世界)
-
适合 DOM 操作
-
对某些受特权保护的 API 访问有限
-
离屏文档(可选)
-
扩展自有的隐藏页面,用于进行类似 DOM 的任务
-
服务工作者(SW)协调;离屏文档完成工作
1.4 预防 MV3 80% 痛苦的设计规则
规则 A:应假设 SW 在空闲时可能被关闭(且可能无通知)。
-
持久化状态 → chrome.storage
-
动态计算 → 每次请求重新加载状态
规则 B:默认情况下 UI 不应直接与标签页进行通信。
-
UI → SW(路由、权限检查)
-
SW → 内容脚本(标签页相关工作) 规则 C:保持工作范围明确且可恢复。
-
短暂处理程序
-
幂等操作
-
长任务的检查点
1.5 最小化架构(复制/粘贴图)
[Popup / Options / Side panel]
|
| runtime.sendMessage({action, requestId})
v
[Service worker (SW)]
- validates permissions + sender
- loads state from storage
- picks target tab
|
| tabs.sendMessage(tabId, ...)
v
[Content script]
- DOM work
- returns result
最小示例
一个最小的 MV3 安全异步消息处理程序(可以很好地用作模板):
javascript
chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
(async () => {
if (msg?.type !== "PING") return;
sendResponse({ ok: true });
})().catch((err) => sendResponse({ ok: false, error: String(err) }));
return true; // keep channel open for async
});
1.6 常见问题
-
将SW当作长时间运行的进程来对待
-
只将"重要的真理"存储在全局变量中
-
使用tabs.sendMessage而不确保存在内容脚本
-
请求过多权限(延迟审核 + 用户不信任)
1.7 检查表
-
\] SW处理器应短小、异步安全且幂等
-
\] UI → SW → tab路由是默认方式
-
Migrate to Manifest V3 (官方): Migrate to Manifest V3
-
Extension service workers (官方): 关于 extension service workers
-
Service worker 生命周期及退出行为 (官方): Service worker 生命周期
-
声明式请求规则 (官方): chrome.declarativeNetRequest
-
Offscreen 文档 (官方): chrome.offscreen