chrome-extension
samber/cc-skills
使用 Manifest V3 构建 Chrome 扩展程序的综合指南。 每当用户提及 Chrome 扩展程序、浏览器扩展程序、manifest.json、内容脚本、服务 worker(在扩展程序上下文中)、弹出窗口、侧边栏、chrome.runtime、chrome.tabs、chrome.storage、chrome.scripting、后台脚本、MV3、Manifest V3 或任何 Chrome 扩展程序 API 时,请使用此技能。 当用户希望将脚本注入网页、在页面与后台之间进行通信,或从内容脚本绕过 CSP 时,也会触发此技能。
...展开全部关于chrome-extension
这是一份关于使用 Manifest V3 构建、调试和发布 Chrome 扩展程序的综合指南,采用路由文档的结构。建议先阅读主文件以了解架构和决策点,随后仅加载相关的、自包含的参考文件以获取实现细节。 参考文件涵盖 manifest.json 的配置与版本控制、服务 worker 的生命周期与状态持久化、内容脚本及隔离环境与主环境之间的注入机制、消息传递与 RPC 层、UI 界面(弹出窗口、选项页面、侧边栏、上下文菜单、命令、通知、万能搜索框、开发者工具面板), chrome.storage 的使用与配额、网络及 CSP 处理、权限、Web 可访问资源、TypeScript 构建配置、发布至 Chrome Web Store、执行上下文流程图以及常见的调试错误。 本教程面向 AI 编程代理,需要使用 Git 和 Node.js,涉及的工具涵盖文件编辑以及 Git、GitHub 和 npm 命令。
架构概述说明,一个扩展程序最多有五个执行上下文,它们通过消息传递进行通信:服务 worker(后台运行、无 DOM、短暂存在、可访问所有 chrome.* API)、弹出窗口、选项页面和侧边栏(均具备完整的 DOM 和 API),以及在网页本身中,处于隔离环境中的内容脚本和位于页面上下文中的主脚本。 图表显示,内容脚本共享 DOM,但拥有自己的 JavaScript 作用域以及对 chrome.runtime 和 chrome.storage 的访问权限,同时仅在网络方面受 CSP 限制;而主环境脚本则拥有完整的页面访问权限,但无法使用 chrome.* API,且完全受 CSP 限制。两者通过共享的 DOM 借助 window.postMessage 进行通信。
通信模式总结如下表:chrome.runtime.sendMessage 用于从任何扩展程序上下文向服务 worker 发送单次请求/响应(最常见的情况), chrome.tabs.sendMessage 用于通过 tabId 将数据从服务 worker 推送至特定标签页;chrome.runtime.connect 端口用于双向流传输和进度跟踪(包括从服务 worker 到弹出窗口);window.postMessage 用于在同一页面内桥接不同执行环境。 由于服务 worker 是短暂存在的,且无法直接向扩展程序页面推送数据,因此本指南建议读者使用端口或 chrome.storage.onChanged(该事件会在所有上下文中同时触发),并指向执行上下文参考文档以获取更详细的流程图以及各上下文的能力与限制分解。 该技能明确指出,不应将其用于框架相关的提问。
常见问题
本文涵盖哪个版本的 Chrome 扩展程序清单?
清单 V3(MV3)。内容涵盖 manifest.json 的设置与修改、图标配置、版本管理,以及更广泛的 MV3 架构、消息传递和发布流程。
该技能如何组织?
采用路由文档形式。您应先阅读主文件 SKILL.md 以了解架构和决策点,然后仅加载相关的、自包含的参考文件(例如 service-worker.md、content-scripts.md 或 messaging-rpc.md)以获取实现细节。
根据本指南,Chrome 扩展程序具有哪些执行上下文?
最多五个通过消息传递进行通信的上下文:扩展程序进程中的服务 worker(后台)、弹出窗口、选项页和侧边栏,以及网页上的内容脚本(隔离环境)和主环境脚本。
对于典型的请求/响应,我应该使用哪种消息传递方法?
从任何扩展程序上下文向服务 worker 发送消息时,应使用 chrome.runtime.sendMessage,指南中指出该方法可处理约 90% 的情况。若需向特定标签页推送消息,请使用 chrome.tabs.sendMessage;若需进行双向流传输,请使用 chrome.runtime.connect 端口。
使用此技能有哪些先决条件?
该技能专为 Claude Code 或类似的 AI 编程代理设计,需要 git 和 node(元数据中列出了 git、node 和 npm)。它不适用于特定框架相关的问题。
所有文件
14个文件references/content-scripts.md12.5KB查看references/execution-contexts.md18.3KB查看references/messaging-rpc.md19.4KB查看references/permissions.md8.0KB查看references/service-worker.md10.9KB 查看 references/typescript-build.md 7.9KB 查看 references/debugging-mistakes.md 9.2KB 查看 references/manifest-v3.md 7.2KB 查看 references/network-csp.md 9.9KB 查看 references/publishing.md6.4KB 查看引用/storage.md9.0KB 查看引用/ui-surfaces.md9.7KB查看引用/web-accessible-resources.md3.1KB 查看SKILL.md16.0 KB 查看This skill covers everything needed to build, debug, and publish Chrome extensions with MV3. It is organized as a routing document: read this file first to understand the architecture and decision points, then load the relevant reference file for implementation details.
Reference files
Read only the reference files relevant to the current task. Each file is self-contained.
| File | When to read |
|---|---|
references/manifest-v3.md | Setting up or modifying manifest.json, configuring icons, versioning |
references/service-worker.md | Background logic, lifecycle, state persistence, alarms, events |
references/content-scripts.md | Injecting code into pages, isolated/main world, dynamic injection, SPA handling, orphaning |
references/messaging-rpc.md | Communication between any contexts, typed protocols, RPC layer, async handler patterns |
references/ui-surfaces.md | Popup, options page, side panel, context menus, commands, notifications, omnibox, devtools panel |
references/storage.md | chrome.storage (local/sync/session), quotas, reactive patterns, framework hooks |
references/network-csp.md | HTTP requests from content scripts, CSP bypass relay, declarativeNetRequest, offscreen docs, CORS |
references/permissions.md | Required/optional permissions, host permissions, activeTab, runtime request flow |
references/web-accessible-resources.md | Exposing extension files to web pages, security implications |
references/typescript-build.md | TypeScript setup, project structure, build tools comparison, bundling |
references/publishing.md | Chrome Web Store submission, review process, rejection reasons, updates, privacy policy |
references/execution-contexts.md | Communication flow diagrams, per-context capabilities/limits, choosing the right messaging method |
references/debugging-mistakes.md | DevTools for extensions, testing SW termination, common gotchas, error patterns |
Architecture overview
A Chrome extension has up to 5 execution contexts that communicate via message passing:
┌──────────────────────────────────────────────────────────┐│ 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) │└──────────────────────────────────────────────────────────┘Communication flows (labeled channels)
┌───────────────────────────────────────────────────────────────────────────┐│ 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) │ ││ └──────────────────┘ └──────────────────┘ │└──────────────────────────────────────────────────────────────────────────┘For detailed flow diagrams (three-layer bridge, cross-extension, storage broadcast) and a per-context breakdown of permissions, limits, and workarounds: → Read references/execution-contexts.md
Communication methods at a glance
| Method | Direction | Best for |
|---|---|---|
chrome.runtime.sendMessage | Any ext context → SW | One-shot request/response (90% of cases) |
chrome.tabs.sendMessage | SW → content script (by tabId) | Pushing data to a specific tab |
chrome.runtime.connect (Port) | Bidirectional | Streaming, progress, SW ↔ popup |
window.postMessage | Between worlds on same page | Page JS ↔ content script bridge |
chrome.storage.onChanged | Broadcast to all contexts | Settings sync, no messaging needed |
→ Full matrix with limits and edge cases: references/execution-contexts.md → Implementation patterns, typed protocols, RPC layer: references/messaging-rpc.md
Key architectural rules
Service worker is ephemeral. It terminates after 30s of inactivity. All state must be persisted to chrome.storage. All event listeners must be registered synchronously at the top level. Never use setTimeout/setInterval for anything beyond a few seconds. → Read
references/service-worker.mdContent scripts run in the page's origin. Network requests from content scripts are subject to the page's CSP and CORS. To bypass, relay through the service worker. → Read
references/network-csp.mdMessaging is the backbone. Every cross-context interaction uses chrome.runtime messaging. The #1 bug: forgetting to
return truefrom async message listeners. → Readreferences/messaging-rpc.mdPermissions determine CWS review speed. Broad host_permissions trigger manual review (weeks). activeTab + optional permissions = fast automated review. → Read
references/permissions.mdPopup is destroyed on blur. Side panel persists. Choose based on interaction duration. → Read
references/ui-surfaces.md
Decision tree: which context handles what?
"I need to run code when the user visits a page"
→ Content script. Static (manifest) for known URL patterns, dynamic (chrome.scripting) for user-triggered injection. Default to isolated world unless you need page JS access. → Read references/content-scripts.md
"I need to make an HTTP request to my API"
- From popup/options/side panel: direct fetch() works (extension origin, no CSP issues)
- From content script on a page with restrictive CSP: relay through service worker
- From service worker: direct fetch() works (requires host_permissions for the target domain) → Read
references/network-csp.md
"I need to store user settings"
- Settings that sync across devices: chrome.storage.sync (100KB limit)
- Large data or caches: chrome.storage.local (10MB, or unlimited with permission)
- Ephemeral state surviving SW restarts: chrome.storage.session → Read
references/storage.md
"I need to modify HTTP headers or block requests"
→ declarativeNetRequest (NOT webRequest, which lost blocking in MV3) → Read references/network-csp.md
"I need the page's JavaScript to talk to my extension"
→ Three-layer bridge: page (window.postMessage) → content script → service worker → Read references/messaging-rpc.md
"I need to understand what each context can and cannot do"
→ Read references/execution-contexts.md — per-context cards listing chrome.* access, DOM, network, storage, lifetime, hard limits, and practical workarounds.
"I need periodic background tasks"
→ chrome.alarms (minimum 30s interval). NOT setTimeout. → Read references/service-worker.md
"I need DOM APIs in the background" (DOMParser, Canvas, Audio)
→ Offscreen document. One per extension, only chrome.runtime available. → Read references/network-csp.md
"I need to authenticate with OAuth"
→ chrome.identity.launchWebAuthFlow() or chrome.identity.getAuthToken() (Google only) → Read references/service-worker.md (identity section)
Workflow: new extension from scratch
Define the manifest with minimum permissions. Start with
activeTab+scripting. → Readreferences/manifest-v3.mdSet up TypeScript and build tooling (or use CRXJS for Vite-based dev). → Read
references/typescript-build.mdImplement the service worker with all event listeners at the top level. → Read
references/service-worker.mdAdd content scripts if you need page interaction. → Read
references/content-scripts.mdBuild UI surfaces (popup, options, side panel) as needed. → Read
references/ui-surfaces.mdWire up messaging between all contexts. → Read
references/messaging-rpc.mdTest with DevTools, specifically test service worker termination. → Read
references/debugging-mistakes.mdPublish to Chrome Web Store. → Read
references/publishing.md
Workflow: adding a feature to an existing extension
- Identify which context the feature belongs to (see decision tree above).
- Read the relevant reference file(s) for that context.
- Check if new permissions are needed. Prefer optional_permissions for new capabilities. → Read
references/permissions.md - Update the manifest if adding new content scripts, UI surfaces, or permissions.
- Handle extension updates gracefully (content script orphaning). → Read
references/content-scripts.md(orphaning section)
Minimal manifest.json template
{ "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" }}→ For the full manifest reference with all fields: references/manifest-v3.md
Code patterns quick reference
Async message handler (the safe pattern)
// Wrap async handlers to avoid the return-true trapfunction 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 bypass relay (content script → service worker → API)
// content-script.tsasync function apiCall(endpoint: string, options?: RequestInit) { return chrome.runtime.sendMessage({ type: "API_RELAY", endpoint, options });}// background.tsconst 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() }; }),);
Persist state across SW restarts
// Use chrome.storage.session for ephemeral statechrome.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 });}
Orphaned content script detection
function isExtensionContextValid(): boolean { try { return !!chrome.runtime?.id; } catch { return false; }}// Before any chrome.runtime callif (!isExtensionContextValid()) { showRefreshBanner(); return;}
What NOT to do
- Do NOT use
eval(),new Function(), or load remote scripts. MV3 forbids it. - Do NOT use
setTimeout/setIntervalfor anything > 5s in service workers. - Do NOT register event listeners inside callbacks or async functions.
- Do NOT use
<all_urls>host permission unless absolutely necessary. - Do NOT rely on DevTools keeping the service worker alive during testing.
- Do NOT forget
return truein async message listeners. - Do NOT use
localStorageorsessionStoragein service workers (they don't exist there). - Do NOT assume content scripts survive extension updates.
- Do NOT use
webRequestblocking (removed in MV3). UsedeclarativeNetRequest. - Do NOT use
chrome.extension.getBackgroundPage()(removed in MV3).





首页
