chrome-extensions について
Chrome Extensionsは、Manifest V3拡張機能の開発とChrome Web Storeへの公開準備を支援するスキルです。拡張機能の構成要素、権限、API、公開に関する実装ルールと注意点をまとめています。
主な機能
- 01Manifest V3の実装ガイド
- 02アイコンとマニフェストの確認
- 03サイドパネルの設定パターン
- 04CSPに準拠したコード実行の案内
- 05権限とAPIの注意点
- 06サービスワーカーとキャプチャの案内
活用シーン
- 01Manifest V3拡張機能の構築
- 02ポップアップやサイドパネルの追加
- 03拡張機能の認証やキャプチャの実装
- 04Chrome Web Store公開の準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ googlechrome/ modern-web-guidance --skill chrome-extensionsインストール後、Claude Code で/chrome-extensionsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/extensions/api-calling.mdauth-identity.mdcontent-scripts.mdcontext-menus.mdcsp-sandbox.mddeclarative-net-request.mddevtools.mdicons.mdmedia-capture.mdmessage-passing.mdomnibox.mdpermissions.mdpopup-ui.mdprompt-api.mdservice-worker.mdside-panel.mdstorage.mdtab-management.mduser-scripts.mdreferences/webstore/chromewebstore-template.mdprivacy-policy.mdreview-checklist.mdstore-listing.md詳細
Chrome 拡張機能
Manifest V3 を使用して本番品質の Chrome 拡張機能を構築し、Chrome ウェブストアに公開します。
パート 1 — 拡張機能の構築
必須ルール
これらは、拡張機能が壊れる最も一般的な原因に対処するものです。違反すると、いずれも拡張機能が動作しなくなります。
1. アイコン:作成したファイルのみを参照するか、アイコンを完全に省略する
❌ BROKEN — referencing files that don't exist or reusing one file for all sizes:
"icons": { "16": "icon.png", "48": "icon.png", "128": "icon.png" }
✅ CORRECT — each size is a separate file at the correct pixel dimensions:
"icons": { "16": "icons/icon-16.png", "48": "icons/icon-48.png", "128": "icons/icon-128.png" }
(where icon-16.png is 16×16px, icon-48.png is 48×48px, icon-128.png is 128×128px)
✅ ALSO CORRECT — omit icons from manifest if you cannot generate real PNG files:
(just remove the "icons" and "default_icon" fields — Chrome uses a default icon)
アイコンを参照する場合は、実際の画像ファイルを必ず作成してください。 スクリプトを使って生成する(references/extensions/icons.md を参照)か、省略してください。存在しないファイルを参照してはいけません。
2. サイドパネル:開く方法を必ず用意する
"side_panel": {"default_path": "..."} を定義しただけでは、サイドパネルは開けるようになりません。起動方法を追加してください。
// In service-worker.js — open side panel on extension icon click
// IMPORTANT: chrome.action.onClicked ONLY fires when there is NO default_popup
chrome.action.onClicked.addListener(async (tab) => {
await chrome.sidePanel.open({ windowId: tab.windowId });
});
拡張機能にポップアップとサイドパネルの両方がある場合は、ポップアップに chrome.sidePanel.open() を呼び出すボタンを追加してください。代わりに、chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true }) を使用することもできます。ただし、プロパティ名は openPanelOnActionClick であり、openPanelOnActionIconClick ではありません。「Icon」版は同期的な TypeError を発生させ、サービスワーカーを警告なく停止させます。setPanelBehavior を使用する場合は、default_popup も定義してはいけません。references/extensions/side-panel.md を参照してください。
3. コードの実行:サンドボックス化された iframe のみを使用する
拡張機能の CSP は、すべての拡張機能ページで eval()、new Function()、インラインの <script> をブロックします。
// ❌ BROKEN — direct iframe DOM access throws SecurityError
iframe.contentDocument.write(html);
// ❌ BROKEN — eval in extension page
eval(userCode); // CSP blocks this
// ✅ OPTION A: Sandbox in manifest + postMessage
// manifest.json: { "sandbox": { "pages": ["sandbox.html"] } }
iframe.contentWindow.postMessage({ html, css, js }, '*');
// sandbox.html receives and runs:
window.addEventListener('message', (e) => { eval(e.data.js); /* allowed in sandbox */ });
// ✅ OPTION B: Blob URL (creates separate origin, bypasses extension CSP)
iframe.src = URL.createObjectURL(new Blob([doc], { type: 'text/html' }));
// ✅ OPTION C: srcdoc
iframe.srcdoc = `<style>${css}</style>${html}<script>${js}<\/script>`;
詳しくは references/extensions/csp-sandbox.md を参照してください。
4. tab.url には tabs 権限が必要
権限がない場合、tab.url はエラーを発生させずに undefined を返します。references/extensions/permissions.md を参照してください。
5. 常に async/await を使用し、.then() のチェーンは使用しない
// ❌ BAD
chrome.tabs.query({active: true, currentWindow: true}).then(tabs => {
chrome.scripting.executeScript({target: {tabId: tabs[0].id}, files: ['content.js']}).then(() => {});
});
// ✅ GOOD
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
await chrome.scripting.executeScript({ target: { tabId: tab.id }, files: ['content.js'] });
非同期処理を行う runtime.onMessage リスナーの場合:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
(async () => {
const data = await chrome.storage.local.get('key');
sendResponse({ data });
})();
return true; // keeps channel open
});
6. コンテンツスクリプト:メインスレッドをブロックしない
多数の DOM 要素を変更する場合は、requestAnimationFrame でまとめて処理し、バッチの間に処理を譲ってください。
async function highlightAll(elements) {
const BATCH = 20;
for (let i = 0; i < elements.length; i += BATCH) {
await new Promise(r => requestAnimationFrame(() => {
elements.slice(i, i + BATCH).forEach(el => el.style.backgroundColor = 'yellow');
r();
}));
if (globalThis.scheduler?.yield) await scheduler.yield();
}
}
references/extensions/content-scripts.md を参照してください。
7. サービスワーカーは一時的に停止するため、変数に状態を保存しない
// ❌ BROKEN — state lost when SW terminates (~30s of inactivity)
let count = 0;
chrome.tabs.onUpdated.addListener(() => { count++; });
// ✅ CORRECT — persist in chrome.storage, read on every event
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
if (changeInfo.status !== 'complete') return;
const { count = 0 } = await chrome.storage.local.get('count');
await chrome.storage.local.set({ count: count + 1 });
await chrome.action.setBadgeText({ text: String(count + 1) });
});
setTimeout/setInterval の代わりに chrome.alarms を使用してください。references/extensions/service-worker.md を参照してください。
8. chrome.identity:拡張機能 ID は開発環境と本番環境で異なる
Google サインインを使用する場合、OAuth の client_id は特定の拡張機能 ID に紐付けられています。この ID は、パッケージ化されていない開発環境と Chrome ウェブストアで異なります。
開発中に ID を固定するには、manifest.json に "key" フィールドを追加してください。
- 拡張機能を一度パッケージ化します(chrome://extensions → Pack)
- .crx から公開鍵を抽出します
- manifest.json に
"key": "MIIBIjANBgkqh..."を追加します
必ず次の内容を記載してください:「Chrome ウェブストアに公開した後、ストアで割り当てられた拡張機能 ID を使って OAuth クライアントを更新してください。」references/extensions/auth-identity.md を参照してください。
9. コンテキストメニュー:操作後にユーザーへフィードバックを表示する
コンテキストメニュー項目が操作(保存、コピーなど)を実行する場合は、ユーザーに完了を知らせてください。通知、バッジの点滅、または挿入したトーストを使用し、操作が何も通知されないまま実行されることがないようにしてください。トーストの完全な実装については references/extensions/context-menus.md を参照してください。
10. Prompt API:サービスワーカー、ポップアップ、サイドパネルで利用可能
LanguageModel API は、サービスワーカー、ポップアップ、サイドパネルなど、すべての拡張機能コンテキストで動作し、追加のマニフェスト権限は必要ありません。拡張機能では、ウェブ上では利用できない LanguageModel.params() も使用できます。
const params = await LanguageModel.params();
// { defaultTopK: 3, maxTopK: 128, defaultTemperature: 1, maxTemperature: 2 }
一般的な Prompt API のパターン(利用可否の確認、セッションの作成、ストリーミング)には、modern-web-guidance スキルを使用してください。拡張機能固有の設定例については references/extensions/prompt-api.md を参照してください。
11. chrome.action API にはマニフェスト内の action が必要
chrome.action.setBadgeText、chrome.action.setIcon、または chrome.action.onClicked を使用するには、空であっても manifest.json に "action" キーが必要です。設定しないと、chrome.action は undefined になります。
// ❌ BROKEN — manifest has no "action" key
await chrome.action.setBadgeText({ text: '5' });
// TypeError: Cannot read properties of undefined (reading 'setBadgeText')
// ✅ FIX — add "action" to manifest.json (at minimum an empty object)
{ "action": {} }
// or with a popup:
{ "action": { "default_popup": "popup/popup.html" } }
12. activeTab は直接のユーザー操作でのみ機能します — サイドパネルからは機能しません
activeTab は、直接のユーザー操作(アクションアイコンのクリック、コンテキストメニュー項目、キーボードショートカット、オムニボックスの候補)の場合にのみ、現在のタブへの一時的なアクセスを許可します。サイドパネルやポップアップ内のボタンをクリックしても許可されません。代わりに tabs と host_permissions を使用してください。詳しくは references/extensions/permissions.md と references/extensions/side-panel.md をご覧ください。
13. DevTools パネルの URL は拡張機能のルートからの相対パスです
DevTools パネルを作成するとき、パネルの HTML パスは、chrome.devtools.panels.create() を呼び出す DevTools ページではなく、拡張機能のルートからの相対パスです。
// ❌ BROKEN — path relative to devtools/ directory
chrome.devtools.panels.create("My Panel", "", "panel/panel.html");
// ✅ CORRECT — full path from extension root
chrome.devtools.panels.create("My Panel", "", "devtools/panel/panel.html");
詳しくは references/extensions/devtools.md をご覧ください。
14. オフスクリーン ドキュメントは、ほとんどの chrome.* API にアクセスできません
オフスクリーン ドキュメント(chrome.offscreen)には厳しい制限があります。chrome.downloads、chrome.tabs、chrome.action などを含む、ほとんどの chrome.* API は利用できません。
// ❌ BROKEN — chrome.downloads is undefined in offscreen documents
chrome.downloads.download({ url, filename: 'recording.webm' }); // TypeError
// ❌ BROKEN — chrome.action is undefined in offscreen documents
chrome.action.setBadgeText({ text: 'REC' }); // TypeError
オフスクリーン ドキュメントで利用できる API は次のとおりです。
chrome.runtime.sendMessage/chrome.runtime.onMessagechrome.runtime.getURL- 標準の Web API(DOM、fetch、MediaRecorder、Canvas、Web Audio など)
**目安:*オフスクリーン ドキュメントでは Web API を使った処理(録画、解析、音声)を行います。chrome. API を使った処理(ダウンロード、バッジの更新、通知)はすべてサービスワーカーで行います。両者の連携には chrome.runtime.sendMessage を使用してください。詳しくは references/extensions/message-passing.md をご覧ください。
15. 通知とバッジアイコンには実在する画像ファイルを指定する必要があります
chrome.notifications.create() には、実際の画像ファイルを指す有効な iconUrl が必要です。
ファイルが存在しないか、パスが間違っている場合、呼び出しは "Unable to download all specified images." というエラーで失敗します。
// ❌ BROKEN — icon file doesn't exist
chrome.notifications.create('reminder', {
type: 'basic',
iconUrl: 'icons/icon-128.png', // File not in extension!
title: 'Reminder',
message: 'Time is up!'
});
// ✅ Generate a data URL at runtime via OffscreenCanvas — no file needed.
// See `references/extensions/icons.md` for a reusable implementation.
const iconUrl = await getIconDataUrl();
chrome.notifications.create('reminder', { type: 'basic', iconUrl, title: 'Reminder', message: 'Time is up!' });
これは、通知、chrome.action.setIcon、コンテキストメニューアイコンなど、chrome.* API で参照されるすべての画像に当てはまります。ファイルを参照する場合、そのファイルが存在していなければなりません。
16. タブのキャプチャ:状態ロックで二重起動を防ぐ
前回のキャプチャがまだ有効な状態で呼び出すと、chrome.tabCapture.getMediaStreamId() は "Cannot capture a tab with an active stream" というエラーで失敗します。拡張機能アイコンを素早く二度クリックすると、簡単にこの問題が発生します。明示的な状態ロックを使用してください。
// ❌ BROKEN — no guard against rapid clicks
let isRecording = false;
chrome.action.onClicked.addListener(async (tab) => {
if (isRecording) { stopRecording(); isRecording = false; }
else { isRecording = true; startRecording(tab); } // Second click = "active stream" error
});
// ✅ CORRECT — use transitional states to lock out concurrent operations
// State machine: 'idle' → 'starting' → 'recording' → 'stopping' → 'idle'
// Store state in chrome.storage.session (survives SW restart, cleared on browser close)
chrome.action.onClicked.addListener(async (tab) => {
const { recordingState = 'idle' } = await chrome.storage.session.get('recordingState');
if (recordingState === 'starting' || recordingState === 'stopping') return;
if (recordingState === 'idle') {
await chrome.storage.session.set({ recordingState: 'starting' });
try {
await startRecording(tab);
await chrome.storage.session.set({ recordingState: 'recording' });
await chrome.action.setBadgeText({ text: 'REC' });
await chrome.action.setBadgeBackgroundColor({ color: '#FF0000' });
} catch (err) {
console.error('Failed to start recording:', err);
await chrome.storage.session.set({ recordingState: 'idle' });
}
} else if (recordingState === 'recording') {
await chrome.storage.session.set({ recordingState: 'stopping' });
try { await stopRecording(); }
finally {
await chrome.storage.session.set({ recordingState: 'idle' });
await chrome.action.setBadgeText({ text: '' });
}
}
});
このパターンは、排他的なリソースを管理するあらゆる chrome API に当てはまります。
chrome.tabCapture、chrome.desktopCapture、chrome.offscreen.createDocument(同時に作成できるオフスクリーン ドキュメントは 1 つのみ)などです。詳しくは references/extensions/media-capture.md をご覧ください。
17. chrome.desktopCapture には URL にアクセスできる対象タブが必要です
サービスワーカーから chrome.desktopCapture.chooseDesktopMedia() を呼び出す場合は、アクティブなタブを targetTab パラメーターとして渡す必要があります。タブオブジェクトの url フィールドを設定するには、"tabs" 権限が必要です。
// ❌ BROKEN — called without targetTab from service worker
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], (streamId) => { ... });
// Error: "A target tab is required when called from a service worker context."
// ❌ BROKEN — tab doesn't have url field (missing "tabs" permission)
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], tab, (streamId) => { ... });
// Error: "targetTab doesn't have URL field set."
// ✅ CORRECT — "tabs" permission in manifest + pass tab object
// manifest.json: { "permissions": ["tabs", "desktopCapture"] }
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], tab, (streamId) => {
if (!streamId) return; // User cancelled
});
**注:**タブのみを録画する場合は、chrome.tabCapture.getMediaStreamId() を優先してください。chrome.desktopCapture は、ユーザーがキャプチャする画面やウィンドウを選択する必要がある場合にのみ使用してください。詳しくは references/extensions/media-capture.md をご覧ください。
18. ユーザースクリプト:見落としやすい4つの落とし穴
chrome.userScripts は実行時にユーザー提供のコードを実行します。スクリプトマネージャーやユーザーの自動化には使用できますが、拡張機能にバンドルされたスクリプトには使用しないでください。
- 有効化されていない場合、プロパティへのアクセス時に API が例外をスローします。 Chrome 138 以降では、ユーザーが拡張機能の詳細ページで「ユーザー スクリプトを許可」をオンにする必要があります。Chrome 138 未満では、デベロッパーモードが必要です。
chrome.userScripts.*を呼び出す前に必ずisUserScriptsAvailable()を呼び出し、false が返された場合はエラー UI を表示してください。 - 拡張機能の更新時に登録済みスクリプトが消去されます。 設定を
chrome.storageに保存し、runtime.onInstalledで理由が"update"の場合に再登録してください。 - メッセージングには明示的なオプトインが必要です。 まず
configureWorld({ messaging: true })を呼び出し、runtime.onMessageではなくruntime.onUserScriptMessageをリッスンしてください。 ScriptSourceの制約: 各jsエントリにはcodeまたはfileのどちらか一方だけを指定する必要があります。idの制約:_で始めることはできません。
references/extensions/user-scripts.md を参照してください。
19. chrome.windows に .query() メソッドはありません — getAll、getLastFocused、または getCurrent を使用してください
chrome.tabs.query() とは異なり、chrome.windows API に .query() メソッドはありません。
// ❌ BROKEN — chrome.windows.query does not exist
const windows = await chrome.windows.query({ focused: true });
// TypeError: chrome.windows.query is not a function
// ✅ CORRECT — use the right method for your need
const focused = await chrome.windows.getLastFocused({ populate: true });
const current = await chrome.windows.getCurrent({ populate: true });
const all = await chrome.windows.getAll({ populate: true });
chrome.windows のメソッド: getAll、getLastFocused、getCurrent、get(windowId)、create、update、remove。references/extensions/tab-management.md を参照してください。
20. サービスワーカー内の chrome.permissions.request() は、メッセージリスナー内で事前に await せずに呼び出す必要があります
UI コンテキスト(サイドパネル、ポップアップ)でのユーザー操作は、chrome.runtime.sendMessage を介してサービスワーカーの onMessage リスナーにも伝播します。ただし、その伝播は同期処理の1回分に限られます。chrome.permissions.request() の呼び出し前にリスナー内で await(短い待機であっても)を行うと、ユーザー操作の情報が失われ、呼び出しは "This function must be called during a user gesture" をスローします。リスナー内では、先に await するものを何も挟まず、最初に呼び出してください。詳しくは references/extensions/permissions.md を参照してください。
常に Manifest V3 を使用
Manifest V2 のコードは生成しないでください。
background.scriptsではなくbackground.service_workerchrome.browserActionではなくchrome.actionchrome.tabs.executeScriptではなくchrome.scripting.executeScripthost_permissionsはpermissionsとは別に指定します- HTML にインラインスクリプトを記述しないでください —
<script src="file.js">を使用してください - インラインイベントハンドラーを使用しないでください —
addEventListenerを使用してください
パート2 — Chrome ウェブストアへの公開
Chrome 拡張機能プロジェクトのすべての Chrome ウェブストア掲載メタデータ、権限の説明、プライバシーに関する開示、バージョン履歴、公開準備状況を一元管理する唯一の情報源として、CHROMEWEBSTORE.md を管理します。
基本的なワークフロー
Chrome 拡張機能プロジェクトについて、ストア掲載に影響する変更を加えるたびに、プロジェクトのルートにある CHROMEWEBSTORE.md を更新(または作成)してください。このファイルには、デベロッパーが Chrome デベロッパー ダッシュボードで入力する必要がある情報がすべて記録されているため、公開時に慌てることなく、1つのドキュメントからコピーして貼り付けられます。
CHROMEWEBSTORE.md を作成するタイミング
次のいずれかに該当したら、作成してください。
- ユーザーが拡張機能を公開したいと言ったとき
- ユーザーが「ストア向けに準備する」または「公開の準備をする」と依頼したとき
- 新しい拡張機能を開発しており、明らかにストアに掲載する予定のとき
- ユーザーからストア掲載要件について質問されたとき
references/webstore/chromewebstore-template.md のテンプレートを出発点として使用してください。ファイルを生成する前に、そのテンプレートを読んでください。
CHROMEWEBSTORE.md を更新するタイミング
次の場合に更新してください。
- ユーザー向けの変更:「Last Updated」の日付を更新し、説明文の機能一覧を更新して、バージョン履歴に項目を追加します
- manifest.json の変更:permissions、host_permissions、content_scripts が変更された場合は、「Permissions Justification」セクションを更新します。各権限について、審査チームが理解できる平易な理由が必要です
- 新しいリリース:バージョン番号、日付、概要を記載した項目を「Version History」に追加します
- プライバシーに関わる変更:データの収集、保存、送信に変更があった場合は、「Privacy & Data Use」セクションとプライバシーポリシーを更新します
- アセットの変更:アイコンや UI に変更があった場合は、更新が必要なスクリーンショットを記載します
- 却下への対応:ユーザーから CWS での却下が報告された場合は、修正内容をファイルに反映し、「Version History」に注記を追加します
記入方法
各セクションには、実際のプロジェクトファイルから情報を取得してください。
manifest.jsonを読み、name、version、description、permissions、host_permissions を確認します- コードベースを調べ、データ収集(ストレージ、fetch 呼び出し、分析)を確認します
- アイコンファイルとその寸法を確認します
- 拡張機能の UI を確認し、説明に記載する機能を把握します
ストア掲載文は、具体的で誠実かつメリットが伝わるトーンで作成してください。Chrome Web Store の審査チームは、曖昧な説明を却下します。「生活が便利になります」は却下されます。「あらゆるウェブページで検索結果をハイライト表示し、ハイライトをローカルリストに保存できます」なら審査に通ります。
**実装の詳細には触れないでください。**ユーザーが知りたいのは拡張機能の仕組みではなく、自分にとって何をしてくれるかです。API、ライブラリ、フレームワーク、コードパターンへの言及はすべて削除してください。
| ❌ 実装の詳細(削除) | ✅ ユーザーにとってのメリット(残す) |
|---|---|
| 「MutationObserver を使用してページの変更を検出します」 | 「閲覧中に新しいコンテンツを自動的に検出します」 |
| 「カスタム要素と Shadow DOM で構築されています」 | 「ページのスタイルに影響を与えず、シームレスに動作します」 |
| 「バックグラウンド処理にサービスワーカーを使用しています」 | 「ブラウザーの動作を遅くすることなく、バックグラウンドで静かに動作します」 |
| 「chrome.storage.sync API を活用しています」 | 「設定がすべてのデバイス間で同期されます」 |
| 「フィルタリングに declarativeNetRequest を実装しています」 | 「ページのコンテンツを読み取ることなく、広告とトラッカーをブロックします」 |
CHROMEWEBSTORE.md のセクション
ファイルを生成する前に references/webstore/chromewebstore-template.md を読み、各セクションの内容と記入方法を確認してください。最もリスクが高いセクションは「Permissions Justification」です。各 permission と host_permission について、具体的で平易な理由を記載してください。「拡張機能の動作に必要です」では却下されます。プライバシーポリシーの作成方法については、references/webstore/privacy-policy.md を読んでください。
公開前チェックリスト
申請前に、references/webstore/review-checklist.md の項目を確認してください。初回申請でよくある失敗は次のとおりです。
- すべての permission と host_permission に、具体的な理由が必要です(「動作に必要」は不可)
- プライバシーポリシーの URL が有効で、データ使用の開示フォームと一致している必要があります
- 1280×800 または 640×400 のスクリーンショットが少なくとも 1 枚必要です
- ZIP から
.git/、node_modules/、.env、CHROMEWEBSTORE.mdを除外する必要があります
ストア掲載文のガイドライン
掲載文のガイドラインとよくある却下理由については、references/webstore/store-listing.md を参照してください。
重要なルール:感情を訴える表現(「検索をまた楽しみましょう」)ではなく、機能(「あらゆるウェブページで検索語をハイライト表示します」)から書き始めてください。
参考ファイル
API のパターンや公開に関するガイダンスの詳細については、コードやコンテンツを作成する前に、該当するファイルをお読みください。
| トピック | 参考資料 |
|---|---|
| 権限 | references/extensions/permissions.md |
| サイドパネル | references/extensions/side-panel.md |
| コンテンツスクリプトと DOM | references/extensions/content-scripts.md |
| ポップアップ | references/extensions/popup-ui.md |
| サービスワーカーのライフタイム | references/extensions/service-worker.md |
| コード実行と CSP | references/extensions/csp-sandbox.md |
| API 呼び出し | references/extensions/api-calling.md |
| Declarative Net Request | references/extensions/declarative-net-request.md |
| Chrome Prompt API | references/extensions/prompt-api.md |
| DevTools パネル | references/extensions/devtools.md |
| 認証 | references/extensions/auth-identity.md |
| コンテキストメニュー | references/extensions/context-menus.md |
| Omnibox | references/extensions/omnibox.md |
| ストレージ | references/extensions/storage.md |
| タブとウィンドウの管理 | references/extensions/tab-management.md |
| タブ/デスクトップのキャプチャ | references/extensions/media-capture.md |
| ユーザースクリプト | references/extensions/user-scripts.md |
| メッセージパッシング | references/extensions/message-passing.md |
| アイコン | references/extensions/icons.md |
| CHROMEWEBSTORE.md テンプレート | references/webstore/chromewebstore-template.md |
| プライバシーポリシーのガイダンス | references/webstore/privacy-policy.md |
| 公開前レビューのチェックリスト | references/webstore/review-checklist.md |
| ストア掲載のヒントと却下理由 | references/webstore/store-listing.md |
出力チェックリスト
提出前にすべての項目を確認してください。
-
manifest_version: 3— V2 APIはどこにも使用していない - manifestで参照されているすべてのアイコンファイルが、正しい寸法の実ファイルとして存在するか、アイコンが省略されている
- サイドパネルに明示的な起動方法がある(manifestで宣言されているだけではない)
- コードの実行にはsandbox/blob/srcdocを使用している — 拡張機能のページで
eval()を使用していない -
tab.urlまたはtab.titleにアクセスする場合、tabs権限が宣言されている - すべてのコードで
async/awaitを使用している —.then()チェーンはない - コンテンツスクリプトで、DOMの更新を
requestAnimationFrameを使ってまとめている - サービスワーカーでグローバル変数に状態を保存していない —
chrome.storageを使用している - HTMLにインラインスクリプトやイベントハンドラーがない
- コンテキストメニューのアクションでユーザーに確認を求める
-
chrome.action.*APIを使用する場合、manifestに"action": {}(またはそれ以上)がある - サイドパネルからタブを読み取る/スクリプトを実行する場合、
tabsとhost_permissionsを使用する(activeTabは使用しない) -
chrome.devtools.panels.create()のDevToolsパネルのパスが、拡張機能のルートからの相対パスになっている - オフスクリーンドキュメントでは
chrome.runtimeメッセージングのみを使用する —chrome.downloads、chrome.actionなどは使用しない -
chrome.notifications、chrome.action.setIconなどで参照する画像が、実在するファイルを指している(またはデータURLを使用している) - タブ/デスクトップのキャプチャで、二重起動エラーを防ぐために状態ロックを使用している
-
chrome.desktopCapture.chooseDesktopMediaで、tabs権限とともにtargetTabを渡している -
chrome.windowsの呼び出しではgetAll/getLastFocused/getCurrentを使用している —.query()は使用しない(存在しないため) - サービスワーカーの
onMessageリスナー内でchrome.permissions.request()を呼び出す際、その前にawaitを挟んでいない(最初の非同期処理の後にユーザー操作の情報が失われるため) -
chrome.userScriptsを使用する前に、利用可能かどうかを確認している(ユーザーが有効にしていない場合、このAPIはエラーをスローする) - ユーザースクリプトの設定を
chrome.storageに保存し、runtime.onInstalledの"update"理由で復元している - ユーザースクリプトがメッセージを送信する前に
configureWorld({ messaging: true })を呼び出している。メッセージの受信にはonMessageではなくonUserScriptMessageを使用している - 各
ScriptSourceエントリにはcodeまたはfileのいずれか一方だけがある(両方でも、どちらもない状態でもない) - ユーザースクリプトの
id値がアンダースコアで始まっていない -
sidePanel.setPanelBehaviorではopenPanelOnActionIconClickではなくopenPanelOnActionClickを使用している - すべての非同期処理でエラー処理を行っている
-
host_permissionsを特定のドメインに限定している(必要な場合を除き<all_urls>は使用しない) - 非同期応答を返す
onMessageリスナーでreturn trueを使用している -
chrome.contextMenusのcontextsで"tab"を使用する場合、Chrome M150以降が必要