chrome-extension について
Chrome 拡張機能の開発者向けに、Manifest V3での構築、デバッグ、公開を扱うリファレンス型スキルです。タスクに応じた資料を案内し、実行コンテキストや実装方法の選択を支援します。
主な機能
- 01Manifest V3の設定と権限
- 02サービスワーカーのライフサイクル案内
- 03コンテンツスクリプトとメッセージングのパターン
- 04ストレージ、ネットワーク、UIのリファレンス
- 05デバッグと公開のガイド
活用シーン
- 01Manifest V3拡張機能の新規作成
- 02新機能に適した実行コンテキストの選択
- 03メッセージングやサービスワーカーの問題調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ samber/ cc-skills --skill chrome-extensionインストール後、Claude Code で/chrome-extensionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/content-scripts.mddebugging-mistakes.mdexecution-contexts.mdmanifest-v3.mdmessaging-rpc.mdnetwork-csp.mdpermissions.mdpublishing.mdservice-worker.mdstorage.mdtypescript-build.mdui-surfaces.mdweb-accessible-resources.md詳細
Chrome 拡張機能の開発(Manifest V3)
このスキルでは、MV3 を使用した Chrome 拡張機能の構築、デバッグ、公開に必要なすべてを網羅しています。ルーティングドキュメントとして構成されているため、まずこのファイルを読んでアーキテクチャと判断のポイントを把握し、その後、実装の詳細に関する該当するリファレンスファイルを読み込んでください。
リファレンスファイル
現在のタスクに関連するリファレンスファイルだけを読んでください。各ファイルは単独で参照できます。
| ファイル | 読むタイミング |
|---|---|
references/manifest-v3.md | manifest.json の設定や変更、アイコンの設定、バージョン管理を行う場合 |
references/service-worker.md | バックグラウンド処理、ライフサイクル、状態の永続化、アラーム、イベントを扱う場合 |
references/content-scripts.md | ページへのコード注入、isolated/main world、動的注入、SPA 対応、孤立化を扱う場合 |
references/messaging-rpc.md | コンテキスト間の通信、型付きプロトコル、RPC レイヤー、非同期ハンドラーパターンを扱う場合 |
references/ui-surfaces.md | ポップアップ、オプションページ、サイドパネル、コンテキストメニュー、コマンド、通知、オムニボックス、DevTools パネルを扱う場合 |
references/storage.md | chrome.storage(local/sync/session)、クォータ、リアクティブなパターン、フレームワークのフックを扱う場合 |
references/network-csp.md | コンテンツスクリプトからの HTTP リクエスト、CSP バイパスの中継、declarativeNetRequest、オフスクリーンドキュメント、CORS を扱う場合 |
references/permissions.md | 必須/任意の権限、ホスト権限、activeTab、ランタイムでのリクエストフローを扱う場合 |
references/web-accessible-resources.md | ウェブページへの拡張機能ファイルの公開と、セキュリティ上の影響を扱う場合 |
references/typescript-build.md | TypeScript の設定、プロジェクト構成、ビルドツールの比較、バンドルを扱う場合 |
references/publishing.md | Chrome ウェブストアへの提出、審査プロセス、却下の理由、更新、プライバシーポリシーを扱う場合 |
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.sendMessage | SW → コンテンツスクリプト(tabId 指定) | 特定のタブへのデータ送信 |
chrome.runtime.connect(Port) | 双方向 | ストリーミング、進捗状況、SW ↔ ポップアップ |
window.postMessage | 同じページ上のワールド間 | ページの JS ↔ コンテンツスクリプトのブリッジ |
chrome.storage.onChanged | すべてのコンテキストへのブロードキャスト | 設定の同期、メッセージング不要 |
→ 制限やエッジケースを含む完全な一覧:references/execution-contexts.md → 実装パターン、型付きプロトコル、RPC レイヤー:references/messaging-rpc.md
主要なアーキテクチャ上のルール
-
サービスワーカーは一時的な存在です。 30 秒間操作がないと終了します。状態はすべて chrome.storage に保存する必要があります。すべてのイベントリスナーは、トップレベルで同期的に登録する必要があります。数秒を超える処理に setTimeout/setInterval を使用しないでください。→
references/service-worker.mdを参照してください。 -
コンテンツスクリプトはページのオリジンで実行されます。 コンテンツスクリプトからのネットワークリクエストは、ページの CSP と CORS の制約を受けます。回避するには、サービスワーカーを介して中継してください。→
references/network-csp.mdを参照してください。 -
メッセージングは基盤です。 コンテキストをまたぐやり取りにはすべて chrome.runtime メッセージングを使用します。最も多いバグは、非同期のメッセージリスナーから
return trueを返し忘れることです。→references/messaging-rpc.mdを参照してください。 -
権限によって CWS の審査速度が変わります。 広範な host_permissions は手動審査(数週間)の対象になります。activeTab とオプションの権限を使えば、自動審査が迅速に行われます。→
references/permissions.mdを参照してください。 -
ポップアップはフォーカスが外れると破棄されます。 サイドパネルは維持されます。操作の継続時間に応じて選択してください。→
references/ui-surfaces.mdを参照してください。
判断ツリー:どのコンテキストで何を処理するか?
「ユーザーがページを訪れたときにコードを実行したい」
→ コンテンツスクリプトを使用します。既知の URL パターンには静的(manifest)、ユーザー操作による挿入には動的(chrome.scripting)を使用します。ページの JavaScript へのアクセスが必要でない限り、デフォルトでは分離ワールドを使用してください。→ references/content-scripts.md を参照してください。
「API に HTTP リクエストを送信したい」
- ポップアップ/オプション/サイドパネルから:直接 fetch() を使用できます(拡張機能のオリジンで実行されるため、CSP の問題はありません)。
- 制限の厳しい CSP が設定されたページ上のコンテンツスクリプトから:サービスワーカーを介して中継します。
- サービスワーカーから:直接 fetch() を使用できます(対象ドメインに対する host_permissions が必要です)。→
references/network-csp.mdを参照してください。
「ユーザー設定を保存したい」
- デバイス間で同期する設定:chrome.storage.sync(上限 100KB)
- 大容量のデータやキャッシュ:chrome.storage.local(10MB、または権限があれば無制限)
- サービスワーカーの再起動後も保持する一時的な状態:chrome.storage.session →
references/storage.mdを参照してください。
「HTTP ヘッダーを変更するか、リクエストをブロックしたい」
→ declarativeNetRequest を使用します(MV3 でブロック機能がなくなった webRequest は使用しません)。→ references/network-csp.md を参照してください。
「ページの JavaScript から拡張機能と通信したい」
→ 3 層のブリッジを使用します:ページ(window.postMessage)→ コンテンツスクリプト → サービスワーカー → references/messaging-rpc.md を参照してください。
「各コンテキストでできること、できないことを把握したい」
→ references/execution-contexts.md を参照してください。chrome.* へのアクセス、DOM、ネットワーク、ストレージ、存続期間、厳格な制限、実用的な回避策をまとめた、コンテキストごとのカードが記載されています。
「バックグラウンドで定期的なタスクを実行したい」
→ chrome.alarms を使用します(最短間隔は 30 秒)。setTimeout は使用しないでください。→ references/service-worker.md を参照してください。
「バックグラウンドで DOM API(DOMParser、Canvas、Audio)を使いたい」
→ オフスクリーンドキュメントを使用します。拡張機能ごとに 1 つだけ作成でき、利用できるのは chrome.runtime のみです。→ references/network-csp.md を参照してください。
「OAuth で認証したい」
→ chrome.identity.launchWebAuthFlow() または chrome.identity.getAuthToken()(Google 専用)を使用します。→ references/service-worker.md の identity セクションを参照してください。
ワークフロー:拡張機能をゼロから作成する
-
最小限の権限で manifest を定義します。
activeTabとscriptingから始めてください。→references/manifest-v3.mdを参照してください。 -
TypeScript とビルドツールをセットアップします(または、Vite ベースの開発には CRXJS を使用します)。→
references/typescript-build.mdを参照してください。 -
サービスワーカーを実装します。 すべてのイベントリスナーをトップレベルに配置してください。→
references/service-worker.mdを参照してください。 -
ページとの連携が必要な場合は、コンテンツスクリプトを追加します。 →
references/content-scripts.mdを参照してください。 -
必要に応じて、UI サーフェス(ポップアップ、オプション、サイドパネル)を構築します。→
references/ui-surfaces.mdを参照してください。 -
すべてのコンテキスト間のメッセージングを設定します。 →
references/messaging-rpc.mdを参照してください。 -
DevTools でテストします。 特に、サービスワーカーの終了をテストしてください。→
references/debugging-mistakes.mdを参照してください。 -
Chrome ウェブストアに公開します。 →
references/publishing.mdを参照してください。
既存の拡張機能に機能を追加するワークフロー
- 機能がどのコンテキストに属するかを特定します(上の判断ツリーを参照)。
- そのコンテキストに関連するリファレンスファイルを読みます。
- 新しい権限が必要か確認します。新しい機能には
optional_permissionsを優先してください。→references/permissions.mdを読みます。 - 新しいコンテンツスクリプト、UI サーフェス、または権限を追加する場合は、マニフェストを更新します。
- 拡張機能の更新を適切に処理します(コンテンツスクリプトの孤立)。→
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() };
}),
);
SW の再起動後も状態を保持する
// 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を使用しないでください(利用できません)。 - コンテンツスクリプトが拡張機能の更新後も存続することを前提にしないでください。
webRequestによるブロッキングを使用しないでください(MV3 で削除されています)。declarativeNetRequestを使用してください。chrome.extension.getBackgroundPage()を使用しないでください(MV3 で削除されています)。