chrome-extension
samber/cc-skills
使用 Manifest V3 開發 Chrome 擴充功能之完整指南。 每當使用者提及 Chrome 擴充功能、瀏覽器擴充功能、manifest.json、內容腳本、服務工作程序(在擴充功能情境下)、彈出視窗、側邊面板、chrome.runtime、chrome.tabs、chrome.storage、chrome.scripting、背景腳本、MV3、Manifest V3 或任何 Chrome 擴充功能 API 時,皆可使用此技能。 當使用者希望將腳本注入網頁、在頁面與背景之間進行通訊,或從內容中繞過 CSP 時,亦會觸發此技能。
...展開全部關於chrome-extension
這是一份採用路由式結構編寫的綜合指南,旨在協助您使用 Manifest V3 建立、除錯及發佈 Chrome 擴充功能。請先閱讀主文件以了解整體架構與決策點,之後再根據需要載入相關且自成一體的參考文件,以掌握實作細節。 參考檔案涵蓋 manifest.json 的設定與版本控制、服務工作程序的生命週期與狀態持久化、內容腳本以及隔離環境與主環境的注入機制、訊息傳遞與 RPC 層、使用者介面元素(彈出視窗、選項頁面、側邊面板、快顯選單、指令、通知、萬用搜尋欄、開發者工具面板), chrome.storage 的使用與配額、網路與 CSP 處理、權限、網頁可存取資源、TypeScript 建置設定、發佈至 Chrome Web Store、執行上下文流程圖,以及常見的除錯錯誤。 本課程專為 AI 編碼代理設計,需具備 Git 與 Node.js 環境,所涉及的工具涵蓋檔案編輯、Git、GitHub 及 npm 指令。
架構概述說明,一個擴充功能最多可擁有五個執行上下文,它們透過訊息傳遞進行通訊:服務工作程式(背景執行、無 DOM、暫存性質、可存取所有 chrome.* API))、彈出視窗、選項頁面及側邊欄(均具備完整的 DOM 及 API),以及在網頁本身中,位於隔離環境中的內容腳本,以及處於頁面上下文中的主腳本。 圖表顯示,內容腳本雖與主腳本共享 DOM,但擁有專屬的 JavaScript 作用域,並可存取 chrome.runtime 和 chrome.storage,同時僅受限於網路層面的 CSP;而主腳本則擁有完整的頁面存取權限,但無法使用 chrome.* API,且完全受 CSP 規範。兩者透過共享的 DOM 利用 window.postMessage 進行通訊。
通訊模式可歸納如下表所示:chrome.runtime.sendMessage 用於從任何擴充功能上下文向服務工作程序發送單次請求/回應(最常見的情況), chrome.tabs.sendMessage 用於根據 tabId 將資料從服務工作程推送到特定分頁;chrome.runtime.connect 埠用於雙向串流與進度追蹤(包含服務工作程至彈出視窗);以及 window.postMessage 用於在同一頁面中橋接不同執行環境。 由於服務工作程式的生命週期短暫且無法直接向擴充功能頁面推送資料,本指南建議讀者使用連接埠或 `chrome.storage.onChanged`(該事件會同時在所有執行上下文中觸發),並指引讀者參閱 `execution-contexts` 參考文件,以獲取更詳細的流程圖以及各執行上下文的功能與限制分析。 該技能明確聲明,不應將其用於框架特定的問題。
常見問題
本指南涵蓋哪個版本的 Chrome 擴充功能清單?
Manifest V3 (MV3)。內容涵蓋 manifest.json 的設定與修改、圖示配置及版本管理,以及更廣泛的 MV3 架構、訊息傳遞與發佈流程。
這項技能是如何組織的?
本指南採用路由式文檔架構。您應先閱讀主文件 SKILL.md 以了解整體架構與決策點,接著僅需載入相關且獨立的參考文件(例如 service-worker.md、content-scripts.md 或 messaging-rpc.md)以獲取實作細節。
根據本指南,Chrome 擴充功能具有哪些執行上下文?
最多五個透過訊息傳遞進行通訊的執行上下文:擴充功能程序內的服務工作者(背景)、彈出視窗、選項頁面及側邊欄,以及網頁上的內容腳本(隔離環境)和主環境腳本。
對於典型的請求/回應,應使用哪種訊息傳遞方法?
從任何擴充功能執行上下文呼叫 `chrome.runtime.sendMessage` 傳送訊息至服務工作程序,指南中指出此方法可處理約百分之九十的情況。若要將訊息推送至特定分頁,請使用 `chrome.tabs.sendMessage`;若要進行雙向串流,請使用 `chrome.runtime.connect` 埠。
使用這項技能有哪些先決條件?
此技能專為 Claude Code 或類似的 AI 編碼代理設計,並需要 git 和 node(元資料中列出了 git、node 和 npm)。它不適用於特定框架相關的問題。
所有檔案
14 個檔案references/content-scripts.md 12.5KB 檢視references/execution-contexts.md 18.3KB 檢視references/messaging-rpc.md 19.4KB 檢視references/permissions.md 8.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.md 9.0KB 檢視 參考資料/ui-surfaces.md 9.7KB 檢視 參考資料/web-accessible-resources.md 3.1KB 檢視 SKILL.md 16.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).
所有檔案
14 個檔案安裝 chrome-extension
請下載並將技能檔案解壓縮至您的 .claude/skills/ 目錄中。
下載 ZIP複製儲存庫並將技能檔案複製到您的專案中。
git clone https://github.com/samber/cc-skills/blob/main/skills/chrome-extension/SKILL.md # Copy SKILL.md to your .claude/skills/ directory
複製





首頁
