mcpField
C
chrome-extension

chrome-extension

github.com/samber开发2414.7k 次安装4 周前更新
代码仓库

关于 chrome-extension

面向 Chrome 扩展开发者的 Manifest V3 参考型 Skill,涵盖构建、调试和发布。它按任务路由到相关资料,帮助选择执行上下文与实现方式。

主要功能

  1. 01Manifest V3 配置与权限
  2. 02Service worker 生命周期指南
  3. 03内容脚本与消息传递模式
  4. 04存储、网络和界面参考
  5. 05调试与发布指南

适用场景

  1. 01从头创建 Manifest V3 扩展
  2. 02为新功能选择执行上下文
  3. 03排查消息传递或 Service worker 问题

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/samber/cc-skills --skill chrome-extension

安装后在 Claude Code 中输入/chrome-extension确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
content-scripts.md
debugging-mistakes.md
execution-contexts.md
manifest-v3.md
messaging-rpc.md
network-csp.md
permissions.md
publishing.md
service-worker.md
storage.md
typescript-build.md
ui-surfaces.md
web-accessible-resources.md

详细介绍

Chrome 扩展开发(Manifest V3)

本技能涵盖使用 MV3 构建、调试和发布 Chrome 扩展所需的一切内容。本文档是一份路由指南:请先阅读本文,了解架构和决策要点,然后加载相关参考文件,查看实现细节。

参考文件

只阅读与当前任务相关的参考文件。每个文件都是独立完整的。

文件何时阅读
references/manifest-v3.md设置或修改 manifest.json、配置图标、版本管理
references/service-worker.md后台逻辑、生命周期、状态持久化、闹钟、事件
references/content-scripts.md向页面注入代码、隔离世界/主世界、动态注入、SPA 处理、孤立问题
references/messaging-rpc.md任意上下文之间的通信、类型化协议、RPC 层、异步处理程序模式
references/ui-surfaces.md弹出窗口、选项页面、侧边栏、上下文菜单、命令、通知、地址栏、开发者工具面板
references/storage.mdchrome.storage(local/sync/session)、配额、响应式模式、框架钩子
references/network-csp.md内容脚本发起的 HTTP 请求、CSP 绕过中继、declarativeNetRequest、离屏文档、CORS
references/permissions.md必需/可选权限、主机权限、activeTab、运行时请求流程
references/web-accessible-resources.md向网页公开扩展文件、安全影响
references/typescript-build.mdTypeScript 设置、项目结构、构建工具比较、打包
references/publishing.mdChrome Web Store 提交、审核流程、拒绝原因、更新、隐私政策
references/execution-contexts.md通信流程图、各上下文的能力/限制、选择合适的消息传递方式
references/debugging-mistakes.md扩展的 DevTools、测试 SW 终止、常见陷阱、错误模式

架构概览

Chrome 扩展最多包含 5 个通过消息传递进行通信的执行上下文:

┌──────────────────────────────────────────────────────────┐
│ Extension Process                                        │
│  ┌─────────────────┐  ┌───────┐  ┌─────────┐  ┌──────┐ │
│  │ Service Worker   │  │ Popup │  │ Options │  │ Side │ │
│  │ (background)     │  │       │  │  Page   │  │Panel │ │
│  │ - No DOM         │  │ Full  │  │  Full   │  │ Full │ │
│  │ - Ephemeral      │  │ DOM   │  │  DOM    │  │ DOM  │ │
│  │ - All chrome.*   │  │ All   │  │  All    │  │ All  │ │
│  │   APIs           │  │ APIs  │  │  APIs   │  │ APIs │ │
│  └────────┬─────────┘  └───┬───┘  └────┬────┘  └──┬───┘ │
│           │ chrome.runtime.sendMessage / connect   │     │
└───────────┼────────────────┼───────────┼──────────┼──────┘
            │                │           │          │
    chrome.tabs.sendMessage  │           │          │
            │                │           │          │
┌───────────┼────────────────┼───────────┼──────────┼──────┐
│ Web Page  ▼                                              │
│  ┌──────────────────┐    ┌──────────────────┐            │
│  │ Content Script    │    │ Main World Script │            │
│  │ (isolated world)  │◄──►│ (page context)    │            │
│  │ - Shared DOM      │    │ - Shared DOM      │            │
│  │ - Own JS scope    │    │ - Page JS scope   │            │
│  │ - chrome.runtime  │    │ - No chrome.* API │            │
│  │ - chrome.storage  │    │ - Full page access│            │
│  │ - Subject to CSP  │    │ - Subject to CSP  │            │
│  │   (network only)  │    │   (fully)         │            │
│  └──────────────────┘    └──────────────────┘            │
│           ▲ window.postMessage                           │
│           │ (through shared DOM)                         │
└──────────────────────────────────────────────────────────┘
通信流程(带标签的通道)
┌───────────────────────────────────────────────────────────────────────────┐
│ Extension Process                                                         │
│                                                                           │
│  ┌─────────────────┐  chrome.runtime   ┌───────┐  ┌─────────┐  ┌──────┐ │
│  │ Service Worker   │◄─.sendMessage()──│ Popup │  │ Options │  │ Side │ │
│  │ (background)     │◄─.connect()──────│       │  │  Page   │  │Panel │ │
│  │                  │                  └───────┘  └─────────┘  └──────┘ │
│  │ - No DOM         │  ┌────────────────────────────────────────────┐   │
│  │ - Ephemeral 30s  │  │ SW cannot push to these pages.             │   │
│  │ - All chrome.*   │  │ Use: ports (.connect) or storage.onChanged │   │
│  └────────┬─────────┘  └────────────────────────────────────────────┘   │
│           │                                                              │
│  chrome.storage.onChanged ◄── fires across ALL contexts simultaneously  │
│                                                                           │
└───────────┼──────────────────────────────────────────────────────────────┘
            │ chrome.tabs.sendMessage(tabId, ...) [SW must know tabId]
            │
┌───────────┼──────────────────────────────────────────────────────────────┐
│ Web Page  ▼                                                              │
│  ┌──────────────────┐  window.postMessage  ┌──────────────────┐         │
│  │ Content Script    │◄───────────────────►│ Main World Script │         │
│  │ (isolated world)  │  Custom DOM events  │ (page context)    │         │
│  │                   │                     │                   │         │
│  │ chrome.runtime ───┼── to/from SW        │ No chrome.* APIs  │         │
│  │ chrome.storage    │                     │ Full page JS      │         │
│  │ Shared DOM        │                     │ Shared DOM        │         │
│  │ Page CSP (network)│                     │ Page CSP (full)   │         │
│  └──────────────────┘                     └──────────────────┘         │
└──────────────────────────────────────────────────────────────────────────┘

有关详细流程图(三层桥接、跨扩展、存储广播)以及各上下文的权限、限制和变通方法:→ 阅读 references/execution-contexts.md

通信方式一览
方式方向最适用于
chrome.runtime.sendMessage任意扩展上下文 → SW一次性请求/响应(占 90% 的情况)
chrome.tabs.sendMessageSW → 内容脚本(按 tabId)向特定标签页推送数据
chrome.runtime.connect (Port)双向流式传输、进度、SW ↔ 弹出窗口
window.postMessage同一页面上的不同世界之间页面 JS ↔ 内容脚本桥接
chrome.storage.onChanged广播到所有上下文同步设置,无需消息传递

→ 完整矩阵及限制和边缘情况:references/execution-contexts.md → 实现模式、类型化协议、RPC 层:references/messaging-rpc.md

核心架构规则
  1. Service worker 是临时的。 空闲 30 秒后会终止。所有状态都必须持久化到 chrome.storage。所有事件监听器都必须在顶层同步注册。除非只延迟几秒,否则绝不要使用 setTimeout/setInterval。→ 阅读 references/service-worker.md

  2. Content script 在页面的来源中运行。 Content script 发出的网络请求受页面的 CSP 和 CORS 限制。要绕过这些限制,请通过 service worker 中转。→ 阅读 references/network-csp.md

  3. 消息传递是核心。 所有跨上下文交互都使用 chrome.runtime 消息传递。最常见的错误:忘记在异步消息监听器中 return true。→ 阅读 references/messaging-rpc.md

  4. 权限决定 CWS 审核速度。 宽泛的 host_permissions 会触发人工审核(数周)。使用 activeTab + 可选权限可快速通过自动审核。→ 阅读 references/permissions.md

  5. Popup 失去焦点时会被销毁。 Side panel 会持续存在。请根据交互时长选择。→ 阅读 references/ui-surfaces.md

决策树:不同任务应由哪个上下文处理?

“我需要在用户访问页面时运行代码”

→ 使用 Content script。对于已知 URL 模式,使用静态方式(manifest);对于用户触发的注入,使用动态方式(chrome.scripting)。除非需要访问页面 JS,否则默认使用隔离世界。→ 阅读 references/content-scripts.md

“我需要向自己的 API 发起 HTTP 请求”
  • 从 popup/options/side panel 发起:直接使用 fetch() 即可(扩展来源,不受 CSP 限制)
  • 从 CSP 严格的页面中的 content script 发起:通过 service worker 中转
  • 从 service worker 发起:直接使用 fetch() 即可(需要针对目标域名配置 host_permissions)→ 阅读 references/network-csp.md
“我需要存储用户设置”
  • 需要跨设备同步的设置:chrome.storage.sync(上限 100KB)
  • 大型数据或缓存:chrome.storage.local(10MB,或在获得权限后不设上限)
  • 需要在 SW 重启后保留的临时状态:chrome.storage.session → 阅读 references/storage.md
“我需要修改 HTTP 标头或拦截请求”

→ 使用 declarativeNetRequest(不要使用 webRequest,MV3 中已移除其拦截功能)→ 阅读 references/network-csp.md

“我需要让页面的 JavaScript 与扩展通信”

→ 使用三层桥接:页面(window.postMessage)→ content script → service worker → 阅读 references/messaging-rpc.md

“我需要了解各个上下文能做什么、不能做什么”

→ 阅读 references/execution-contexts.md — 其中的各上下文卡片列出了 chrome.* 访问权限、DOM、网络、存储、生命周期、硬性限制和实用变通方法。

“我需要定期执行后台任务”

→ 使用 chrome.alarms(最短间隔为 30 秒)。不要使用 setTimeout。→ 阅读 references/service-worker.md

“我需要在后台使用 DOM API”(DOMParser、Canvas、Audio)

→ 使用 Offscreen document。每个扩展只能有一个,且只能使用 chrome.runtime。→ 阅读 references/network-csp.md

“我需要通过 OAuth 进行身份验证”

→ 使用 chrome.identity.launchWebAuthFlow() 或 chrome.identity.getAuthToken()(仅限 Google)→ 阅读 references/service-worker.md(identity 部分)

工作流:从零开始创建扩展

  1. 定义 manifest,并使用最少权限。从 activeTab + scripting 开始。→ 阅读 references/manifest-v3.md

  2. 设置 TypeScript 和构建工具(或使用 CRXJS 进行基于 Vite 的开发)。→ 阅读 references/typescript-build.md

  3. 实现 service worker,并在顶层注册所有事件监听器。→ 阅读 references/service-worker.md

  4. 如果需要与页面交互,添加 content script。 → 阅读 references/content-scripts.md

  5. 按需构建 UI 界面(popup、options、side panel)。→ 阅读 references/ui-surfaces.md

  6. 配置所有上下文之间的消息传递。 → 阅读 references/messaging-rpc.md

  7. 使用 DevTools 测试,尤其要测试 service worker 终止的情况。 → 阅读 references/debugging-mistakes.md

  8. 发布到 Chrome Web Store。 → 阅读 references/publishing.md

工作流:向现有扩展添加功能

  1. 确定该功能所属的上下文(参见上方决策树)。
  2. 阅读该上下文的相关参考文件。
  3. 检查是否需要新权限。新增功能优先使用 optional_permissions。→ 阅读 references/permissions.md
  4. 如果要添加新的内容脚本、UI 界面或权限,请更新清单。
  5. 妥善处理扩展更新(内容脚本孤立)。→ 阅读 references/content-scripts.md(孤立部分)

最小 manifest.json 模板

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0.0",
  "description": "What it does in one sentence",
  "permissions": ["storage", "activeTab", "scripting"],
  "action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon16.png",
      "48": "icons/icon48.png",
      "128": "icons/icon128.png"
    }
  },
  "background": {
    "service_worker": "background.js",
    "type": "module"
  },
  "icons": {
    "16": "icons/icon16.png",
    "48": "icons/icon48.png",
    "128": "icons/icon128.png"
  }
}

→ 如需查看包含所有字段的完整清单参考,请参阅:references/manifest-v3.md

代码模式速查

异步消息处理程序(安全模式)
// Wrap async handlers to avoid the return-true trap
function asyncHandler(
  fn: (msg: any, sender: chrome.runtime.MessageSender) => Promise<any>,
) {
  return (
    message: any,
    sender: chrome.runtime.MessageSender,
    sendResponse: (r: any) => void,
  ) => {
    fn(message, sender)
      .then(sendResponse)
      .catch((e) => sendResponse({ __error: true, message: e.message }));
    return true; // literal true, not Promise<true>
  };
}

chrome.runtime.onMessage.addListener(
  asyncHandler(async (msg, sender) => {
    if (msg.type === "FETCH") {
      const res = await fetch(msg.url);
      return { ok: res.ok, data: await res.text() };
    }
  }),
);
CSP 绕过中继(内容脚本 → 服务工作线程 → API)
// content-script.ts
async function apiCall(endpoint: string, options?: RequestInit) {
  return chrome.runtime.sendMessage({ type: "API_RELAY", endpoint, options });
}

// background.ts
const ALLOWED_ENDPOINTS = ["https://api.example.com"];
chrome.runtime.onMessage.addListener(
  asyncHandler(async (msg) => {
    if (msg.type !== "API_RELAY") return;
    if (!ALLOWED_ENDPOINTS.some((e) => msg.endpoint.startsWith(e))) {
      throw new Error("Blocked endpoint");
    }
    const res = await fetch(msg.endpoint, msg.options);
    return { ok: res.ok, status: res.status, data: await res.text() };
  }),
);
在服务工作线程重启后保留状态
// Use chrome.storage.session for ephemeral state
chrome.storage.session.setAccessLevel({
  accessLevel: "TRUSTED_AND_UNTRUSTED_CONTEXTS",
});

async function getState<T>(key: string, fallback: T): Promise<T> {
  const result = await chrome.storage.session.get(key);
  return result[key] ?? fallback;
}
async function setState<T>(key: string, value: T): Promise<void> {
  await chrome.storage.session.set({ [key]: value });
}
孤立内容脚本检测
function isExtensionContextValid(): boolean {
  try {
    return !!chrome.runtime?.id;
  } catch {
    return false;
  }
}

// Before any chrome.runtime call
if (!isExtensionContextValid()) {
  showRefreshBanner();
  return;
}

禁止事项

  • 不要使用 eval()、new Function() 或加载远程脚本。MV3 禁止这些行为。
  • 不要在服务工作线程中使用超过 5 秒的 setTimeout/setInterval。
  • 不要在回调或异步函数中注册事件监听器。
  • 除非绝对必要,否则不要使用 <all_urls> 主机权限。
  • 测试时不要依赖 DevTools 让服务工作线程保持运行。
  • 不要忘记在异步消息监听器中添加 return true。
  • 不要在服务工作线程中使用 localStorage 或 sessionStorage(这些 API 在其中不存在)。
  • 不要假设内容脚本在扩展更新后仍会继续运行。
  • 不要使用 webRequest 阻止功能(已在 MV3 中移除)。请使用 declarativeNetRequest。
  • 不要使用 chrome.extension.getBackgroundPage()(已在 MV3 中移除)。

评论

支持 Markdown