DevTools 拡張機能は、拡張機能に追加された DevTools ページを通じて DevTools 固有の拡張機能 API にアクセスすることで、Chrome DevTools に機能を追加します。
DevTools 固有の拡張機能 API には、次のものがあります。
DevTools ページ
DevTools ウィンドウが開くと、DevTools 拡張機能は、ウィンドウが開いている間存在する DevTools ページのインスタンスを作成します。このページは DevTools API と拡張機能 API にアクセスでき、次の操作を行うことができます。
devtools.panelsAPI を使用してパネルを作成し、操作します。たとえば、他の拡張機能ページをパネルまたはサイドバーとして DevTools ウィンドウに追加できます。devtools.inspectedWindowAPI を使用して、検査対象のウィンドウに関する情報を取得し、検査対象のウィンドウ内のコードを評価します。devtools.networkAPI を使用してネットワーク リクエストに関する情報を取得します。devtools.recorderAPI を使用してレコーダー パネルを拡張します。devtools.performanceAPI を使用して、パフォーマンス パネルの記録ステータスに関する情報を取得します。
DevTools ページは拡張機能 API に直接アクセスできます。これには、メッセージ パッシングを使用して Service Worker と通信できることも含まれます。
DevTools 拡張機能を作成する
拡張機能の DevTools ページを作成するには、拡張機能のマニフェストに devtools_page フィールドを追加します。
{
"name": ...
"version": "1.0",
"devtools_page": "devtools.html",
...
}
devtools_page フィールドは HTML ページを指している必要があります。DevTools ページは拡張機能に対してローカルである必要があるため、相対 URL を使用して指定することをおすすめします。
browser.devtools API のメンバーは、DevTools ウィンドウが開いている間、そのウィンドウ内で読み込まれたページでのみ使用できます。コンテンツ スクリプトや他の拡張機能ページは、これらの API にアクセスできません。
ブラウザの名前空間と DevTools 拡張機能
Chrome バージョン 152 以降では、DevTools ページを含む拡張機能で browser 名前空間を使用できます。
Chrome バージョン 152 より前のバージョンでは、devtools_page を宣言する拡張機能に対して browser 名前空間が無効になっていました。オプトアウトは拡張機能全体に適用され、DevTools ページだけでなく、拡張機能 API が実行されるすべてのスクリプト コンテキストに適用されます。
原因は webextension-polyfill との互換性のギャップでした。Chrome 152 より前の browser.devtools.* API はコールバック専用で、Promise をネイティブに返さなかったため、DevTools 拡張機能は通常、ポリフィルを使用してラップしていました。polyfill は、browser が定義されている場合は常にラッピングをスキップし、ホストがすでに処理を完了していると想定します。Chrome でこれらの拡張機能に対して browser が有効になっていた場合、ポリフィルは no-op になり、browser.devtools.* 呼び出しは Promise を返さなくなります。browser をオフにすると、ポリフィルがラップし続けます。
同じオプトアウトにより、これらの拡張機能では、runtime.onMessage の Promise レスポンスなど、Chrome 148 の他のメッセージング API の変更も無効になりました。DevTools API が Promise をネイティブにサポートするようになったため、この制限は解除されました。
DevTools の UI 要素: パネルとサイドバー ペイン
DevTools 拡張機能では、ブラウザ アクション、コンテキスト メニュー、ポップアップなどの通常の拡張機能の UI 要素に加えて、DevTools ウィンドウに UI 要素を追加できます。
- パネルとは、[要素]、[ソース]、[ネットワーク] パネルなどの最上位のタブのことです。
- サイドバー ペインには、パネルに関連する補足的な UI が表示されます。[Elements] パネルの [Styles]、[Computed Styles]、[Event Listeners] ペインは、サイドバー ペインの例です。使用している Chrome のバージョンと DevTools ウィンドウがドッキングされている場所に応じて、サイドバー ペインは次の例の画像のように表示されることがあります。
各パネルは独自の HTML ファイルであり、他のリソース(JavaScript、CSS、画像など)を含めることができます。基本的なパネルを作成するには、次のコードを使用します。
browser.devtools.panels.create("My Panel",
"MyPanelIcon.png",
"Panel.html",
function(panel) {
// code invoked on panel creation
}
);
パネルまたはサイドバー ペインで実行される JavaScript は、DevTools ページと同じ API にアクセスできます。
基本的なサイドバー ペインを作成するには、次のコードを使用します。
browser.devtools.panels.elements.createSidebarPane("My Sidebar",
function(sidebar) {
// sidebar initialization code here
sidebar.setObject({ some_data: "Some data to show" });
});
サイドバー ペインにコンテンツを表示する方法はいくつかあります。
- HTML コンテンツ:
setPage()を呼び出して、ペインに表示する HTML ページを指定します。 - JSON データ: JSON オブジェクトを
setObject()に渡します。 - JavaScript 式:
setExpression()に式を渡します。DevTools は、検査対象のページのコンテキストで式を評価し、戻り値を表示します。
setObject() と setExpression() の両方で、ペインには DevTools コンソールに表示される値が表示されます。ただし、setExpression() では DOM 要素と任意の JavaScript オブジェクトを表示できますが、setObject() では JSON オブジェクトのみがサポートされます。
拡張機能コンポーネント間で通信する
以降のセクションでは、DevTools 拡張機能のコンポーネントが相互に通信できるようにする便利な方法について説明します。
コンテンツ スクリプトを挿入する
コンテンツ スクリプトを挿入するには、scripting.executeScript() を使用します。
// DevTools page -- devtools.js
browser.scripting.executeScript({
target: {
tabId: browser.devtools.inspectedWindow.tabId
},
files: ["content_script.js"]
});
検査対象のウィンドウのタブ ID は、inspectedWindow.tabId プロパティを使用して取得できます。
コンテンツ スクリプトがすでに挿入されている場合は、メッセージング API を使用して通信できます。
検査ウィンドウで JavaScript を評価する
inspectedWindow.eval() メソッドを使用すると、検査対象のページのコンテキストで JavaScript コードを実行できます。eval() メソッドは、DevTools のページ、パネル、サイドバー ペインから呼び出すことができます。
デフォルトでは、式はページのメインフレームのコンテキストで評価されます。inspectedWindow.eval() は、DevTools コンソールに入力されたコードと同じスクリプト実行コンテキストとオプションを使用します。これにより、eval() を使用する際に DevTools のコンソール ユーティリティ API 機能にアクセスできます。たとえば、HTML ドキュメントの <head> セクション内の最初のスクリプト要素を検査するには、次のようにします。
browser.devtools.inspectedWindow.eval(
"inspect($$('head script')[0])",
function(result, isException) { }
);
inspectedWindow.eval() を呼び出してコンテンツ スクリプトと同じコンテキストで式を評価するときに、useContentScriptContext を true に設定することもできます。このオプションを使用するには、eval() を呼び出す前に、executeScript() を呼び出すか、manifest.json ファイルでコンテンツ スクリプトを指定して、静的コンテンツ スクリプト宣言を使用します。コンテンツ スクリプトのコンテキストが読み込まれた後、このオプションを使用して追加のコンテンツ スクリプトを挿入することもできます。
選択した要素をコンテンツ スクリプトに渡す
コンテンツ スクリプトは、現在選択されている要素に直接アクセスできません。ただし、inspectedWindow.eval() を使用して実行するコードは、DevTools コンソールと Console Utilities API にアクセスできます。たとえば、評価されたコードでは、$0 を使用して選択された要素にアクセスできます。
選択した要素をコンテンツ スクリプトに渡すには:
選択した要素を引数として受け取るメソッドをコンテンツ スクリプトに作成します。
function setSelectedElement(el) { // do something with the selected element }useContentScriptContext: trueオプションを指定してinspectedWindow.eval()を使用し、DevTools ページからメソッドを呼び出します。browser.devtools.inspectedWindow.eval("setSelectedElement($0)", { useContentScriptContext: true });
useContentScriptContext: true オプションは、式がコンテンツ スクリプトと同じコンテキストで評価される必要があることを指定します。これにより、setSelectedElement メソッドにアクセスできます。
リファレンス パネルの window を取得する
devtools パネルから postMessage() を呼び出すには、その window オブジェクトへの参照が必要です。panel.onShown イベント ハンドラからパネルの iframe ウィンドウを取得します。
extensionPanel.onShown.addListener(function (extPanelWindow) {
extPanelWindow instanceof Window; // true
extPanelWindow.postMessage( // …
});
挿入されたスクリプトから DevTools ページにメッセージを送信する
コンテンツ スクリプトなしでページに直接挿入されたコード(<script> タグの追加や inspectedWindow.eval() の呼び出しなど)は、runtime.sendMessage() を使用して DevTools ページにメッセージを送信できません。代わりに、挿入されたスクリプトを仲介役となるコンテンツ スクリプトと組み合わせて、window.postMessage() メソッドを使用することをおすすめします。次の例では、前のセクションのバックグラウンド スクリプトを使用します。
// injected-script.js
window.postMessage({
greeting: 'hello there!',
source: 'my-devtools-extension'
}, '*');
// content-script.js
window.addEventListener('message', function(event) {
// Only accept messages from the same frame
if (event.source !== window) {
return;
}
var message = event.data;
// Only accept messages that we know are ours. Note that this is not foolproof
// and the page can easily spoof messages if it wants to.
if (typeof message !== 'object' || message === null ||
message.source !== 'my-devtools-extension') {
return;
}
browser.runtime.sendMessage(message);
});
その他の代替メッセージ パッシング手法については、GitHub をご覧ください。
DevTools の開閉を検出する
DevTools ウィンドウが開いているかどうかをトラッキングするには、Service Worker に onConnect リスナーを追加し、DevTools ページから connect() を呼び出します。各タブで独自の DevTools ウィンドウを開くことができるため、複数の接続イベントを受け取る可能性があります。DevTools ウィンドウが開いているかどうかを追跡するには、次の例に示すように、接続イベントと切断イベントをカウントします。
// background.js
var openCount = 0;
browser.runtime.onConnect.addListener(function (port) {
if (port.name == "devtools-page") {
if (openCount == 0) {
alert("DevTools window opening.");
}
openCount++;
port.onDisconnect.addListener(function(port) {
openCount--;
if (openCount == 0) {
alert("Last DevTools window closing.");
}
});
}
});
DevTools ページは次のような接続を作成します。
// devtools.js
// Create a connection to the service worker
const serviceWorkerConnection = browser.runtime.connect({
name: "devtools-page"
});
// Send a periodic heartbeat to keep the port open.
setInterval(() => {
port.postMessage("heartbeat");
}, 15000);
DevTools 拡張機能の例
このページの例は、次のページから引用しています。
- Polymer Devtools Extension - ホストページで実行されている多くのヘルパーを使用して、DOM/JS 状態をクエリし、カスタム パネルに送り返します。
- React DevTools 拡張機能 - レンダラのサブモジュールを使用して、DevTools UI コンポーネントを再利用します。
- Ember Inspector - Chrome と Firefox の両方のアダプタで共有される拡張機能のコア。
- Coquette-inspect - ホストページにデバッグ エージェントが挿入された、クリーンな React ベースの拡張機能。
- サンプル拡張機能には、インストール、試用、学習に役立つ拡張機能が多数用意されています。
詳細
拡張機能で使用できる標準 API については、browser.* API と ウェブ API。
フィードバックをお寄せください皆様からのコメントや提案は、API の改善に役立てさせていただきます。
例
DevTools API を使用する例については、サンプルをご覧ください。