DevTools の拡張

DevTools 拡張機能は、拡張機能に追加された DevTools ページから DevTools 固有の拡張機能 API にアクセスして、Chrome DevTools に機能を追加します。

DevTools ページが検査対象のウィンドウと Service Worker と通信していることを示すアーキテクチャ図。Service Worker がコンテンツ スクリプトと通信し、拡張機能 API にアクセスしている様子が示されています。DevTools ページは、パネルの作成などの DevTools API にアクセスできます。
DevTools 拡張機能のアーキテクチャ。

DevTools 固有の拡張機能 API には、次のものがあります。

DevTools ページ

DevTools ウィンドウが開くと、DevTools 拡張機能は、ウィンドウが開いている間存在する DevTools ページのインスタンスを作成します。このページは DevTools API と拡張機能 API にアクセスでき、次のことができます。

DevTools ページは、拡張機能 API に直接アクセスできます。これには、Service Worker と 通信するために メッセージ パッシングを使用できることも含まれます。

DevTools 拡張機能を作成する

拡張機能の DevTools ページを作成するには、拡張機能マニフェストに devtools_page フィールドを追加します。

{
  "name": ...
  "version": "1.0",
  "devtools_page": "devtools.html",
  ...
}

devtools_page フィールドは HTML ページを指している必要があります。DevTools ページは拡張機能に対してローカルである必要があるため、相対 URL を使用して指定することをおすすめします。

chrome.devtools API のメンバーは、DevTools ウィンドウが開いている間、そのウィンドウ内に読み込まれたページでのみ使用できます。コンテンツ スクリプトや他の拡張機能ページは、これらの API にアクセスできません。

ブラウザの名前空間と DevTools 拡張機能

Chrome 148 で導入された browser 名前空間 は、 devtools_page を宣言する拡張機能では無効になっています。オプトアウトは、DevTools ページだけでなく、拡張機能 API が実行されるすべてのスクリプト コンテキストなど、拡張機能全体に適用されます。これらの拡張機能では、引き続き chrome.* を使用してください。

これは、 webextension-polyfillとの互換性の問題が原因です。 chrome.devtools.* API はコールバックのみで、ネイティブで Promise を返さないため、DevTools 拡張機能は通常、polyfill を使用してラップします。polyfill は、browser が定義されている場合は常にラップをスキップし、ホストがすでに処理を完了していると想定します。Chrome がこれらの拡張機能で browser を有効にすると、polyfill は no-op になり、chrome.devtools.* 呼び出しは Promise を返さなくなります。browser を無効にすると、polyfill は引き続きラップできます。

同じオプトアウトにより、これらの拡張機能に対する Chrome 148 の他のメッセージング API の変更も無効になります。これには、Promise responses in runtime.onMessageが含まれます。この制限は、DevTools API がネイティブで Promise をサポートすると解除されます。

DevTools UI 要素: パネルとサイドバー ペイン

ブラウザ アクション、コンテキスト メニュー、ポップアップなど、通常の拡張機能 UI 要素に加えて、DevTools 拡張機能では UI 要素を DevTools ウィンドウに追加できます。

  • パネルは、[要素]、[ソース]、[ネットワーク] パネルなどの最上位タブです。
  • サイドバー ペインには、パネルに関連する補足 UI が表示されます。[要素] パネルの [スタイル]、[計算済みスタイル]、[イベント リスナー] ペインは、サイドバー ペインの例です。使用している Chrome のバージョンと DevTools ウィンドウのドッキング位置によっては、サイドバー ペインが次の例の画像のように表示されることがあります。
[要素] パネルと [スタイル] サイドバー ペインが表示されている DevTools ウィンドウ。
[要素] パネルと [スタイル] サイドバー ペインが表示された DevTools ウィンドウ。

各パネルは独自の HTML ファイルで、他のリソース(JavaScript、CSS、画像など)を含めることができます。基本的なパネルを作成するには、次のコードを使用します。

chrome.devtools.panels.create("My Panel",
    "MyPanelIcon.png",
    "Panel.html",
    function(panel) {
      // code invoked on panel creation
    }
);

パネルまたはサイドバー ペインで実行される JavaScript は、DevTools ページと同じ API にアクセスできます。

基本的なサイドバー ペインを作成するには、次のコードを使用します。

chrome.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
chrome.scripting.executeScript({
  target: {
    tabId: chrome.devtools.inspectedWindow.tabId
  },
  files: ["content_script.js"]
});

検査対象のウィンドウのタブ ID は、 inspectedWindow.tabId プロパティを使用して取得できます。

コンテンツ スクリプトがすでに挿入されている場合は、メッセージング API を使用して通信できます。

検査対象のウィンドウで JavaScript を評価する

inspectedWindow.eval() メソッドを使用すると、検査対象のページのコンテキストで JavaScript コードを実行できます。eval() メソッドは、DevTools ページ、パネル、サイドバー ペインから呼び出すことができます。

をご覧ください。

デフォルトでは、式はページのメインフレームのコンテキストで評価されます。 inspectedWindow.eval() は、DevTools コンソールに入力されたコード と同じスクリプト実行コンテキストとオプションを使用します。これにより、DevTools Console Utilities API 機能に eval() を使用するときにアクセスできます。たとえば、これを使用して HTML ドキュメントの <head> セクション内の最初のスクリプト要素を検査します。

chrome.devtools.inspectedWindow.eval(
  "inspect($$('head script')[0])",
  function(result, isException) { }
);

inspectedWindow.eval() を呼び出すときに useContentScriptContexttrue に設定して、コンテンツ スクリプトと同じコンテキストで式を評価することもできます。このオプションを使用するには、eval() を呼び出す前に 静的コンテンツ スクリプト宣言 を使用します。これを行うには、executeScript() を呼び出すか、manifest.json ファイルで content script を指定します。コンテンツ スクリプト コンテキストが読み込まれたら、このオプションを使用して追加のコンテンツ スクリプトを挿入することもできます。

選択した要素をコンテンツ スクリプトに渡す

コンテンツ スクリプトは、現在選択されている要素に直接アクセスできません。ただし、inspectedWindow.eval() を使用して実行するコードは、DevTools コンソールと Console Utilities API にアクセスできます。たとえば、評価されたコードで $0 を使用して、選択した要素にアクセスできます。

選択した要素をコンテンツ スクリプトに渡すには:

  1. 選択した要素を引数として受け取るメソッドをコンテンツ スクリプトに作成します。

    function setSelectedElement(el) {
        // do something with the selected element
    }
    
  2. useContentScriptContext: true オプションを指定して inspectedWindow.eval() を使用し、DevTools ページからメソッドを呼び出します。

    chrome.devtools.inspectedWindow.eval("setSelectedElement($0)",
        { useContentScriptContext: true });
    

useContentScriptContext: true オプションは、式をコンテンツ スクリプトと同じコンテキストで評価する必要があることを指定するため、setSelectedElement メソッドにアクセスできます。

リファレンス パネルの window を取得する

devtools パネルから postMessage() を呼び出すには、その window オブジェクトへの参照が必要です。 パネルの iframe ウィンドウを panel.onShown イベント ハンドラから取得します。

extensionPanel.onShown.addListener(function (extPanelWindow) {
    extPanelWindow instanceof Window; // true
    extPanelWindow.postMessage( // …
});

挿入されたスクリプトから DevTools ページにメッセージを送信する

コンテンツ スクリプトなしでページに直接挿入されたコード(<script> タグの追加や inspectedWindow.eval() の呼び出しなど)は、 DevTools ページに runtime.sendMessage() を使用してメッセージを送信できません。代わりに、挿入されたスクリプトを仲介として機能するコンテンツ スクリプトと組み合わせて、 the 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;
  }

  chrome.runtime.sendMessage(message);
});

他の代替メッセージ パッシング手法については、GitHub をご覧ください

DevTools の開閉を検出する

DevTools ウィンドウが開いているかどうかをトラッキングするには、onConnect リスナー を Service Worker に追加し、DevTools ページから connect() を呼び出します。各タブで独自の DevTools ウィンドウを開くことができるため、複数の connect イベントを受信する可能性があります。 DevTools ウィンドウが開いているかどうかをトラッキングするには、次の例に示すように、connect イベントと disconnect イベントをカウントします。

// background.js
var openCount = 0;
chrome.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 = chrome.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 Extension - レンダラ サブモジュールを使用して DevTools UI コンポーネントを再利用します。
  • Ember Inspector \- Chrome と Firefox の両方のアダプターを備えた共有拡張機能コア。
  • Coquette-inspect - デバッグ エージェントがホストページに挿入された、クリーンな React ベースの拡張機能。
  • サンプル拡張機能には、インストール、試用、学習 に役立つ拡張機能が他にもあります。

詳細

拡張機能で使用できる標準 API については、chrome.* APIウェブ API をご覧ください。

フィードバックをお寄せください。 コメントやご提案は、API の改善に役立ちます。

DevTools API を使用する例については、サンプルをご覧ください。