DevTools uitbreiden

Overzicht

Een DevTools-extensie voegt functionaliteit toe aan Chrome DevTools. Het kan nieuwe UI-panelen en zijbalken toevoegen, communiceren met de geïnspecteerde pagina, informatie krijgen over netwerkverzoeken en meer. Bekijk aanbevolen DevTools-extensies . DevTools-extensies hebben toegang tot een extra set DevTools-specifieke extensie-API's:

Een DevTools-extensie is gestructureerd zoals elke andere extensie: deze kan een achtergrondpagina, inhoudsscripts en andere items bevatten. Bovendien heeft elke DevTools-extensie een DevTools-pagina, die toegang heeft tot de DevTools API's.

Architectuurdiagram dat de DevTools-pagina toont die communiceert met het geïnspecteerde venster en de achtergrondpagina. Er wordt getoond dat de achtergrondpagina communiceert met de inhoudsscripts en toegang heeft tot extensie-API's. De DevTools-pagina heeft toegang tot de DevTools API's, waarmee u bijvoorbeeld panelen kunt maken.

De DevTools-pagina

Telkens wanneer een DevTools-venster wordt geopend, wordt er een exemplaar van de DevTools-pagina van de extensie gemaakt. De DevTools-pagina bestaat gedurende de levensduur van het DevTools-venster. De DevTools-pagina heeft toegang tot de DevTools API's en een beperkt aantal extensie-API's. Concreet kan de DevTools-pagina:

  • Creëer en communiceer met panelen met behulp van de devtools.panels API's.
  • Krijg informatie over het geïnspecteerde venster en evalueer code in het geïnspecteerde venster met behulp van de devtools.inspectedWindow API's.
  • Krijg informatie over netwerkverzoeken met behulp van de devtools.network API's.

De DevTools-pagina kan de meeste extensie-API's niet rechtstreeks gebruiken. Het heeft toegang tot dezelfde subset van de extension en runtime API's waartoe een inhoudsscript toegang heeft. Net als een inhoudsscript kan een DevTools-pagina communiceren met de achtergrondpagina met behulp van Message Passing . Zie Een inhoudsscript injecteren voor een voorbeeld.

Een DevTools-extensie maken

Als u een DevTools-pagina voor uw extensie wilt maken, voegt u het veld devtools_page toe aan het extensiemanifest:

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

Voor elk geopend DevTools-venster wordt een exemplaar gemaakt van de devtools_page die is opgegeven in het manifest van uw extensie. De pagina kan andere extensiepagina's toevoegen als panelen en zijbalken aan het DevTools-venster met behulp van de devtools.panels API.

De chrome.devtools.* API-modules zijn alleen beschikbaar voor de pagina's die in het DevTools-venster zijn geladen. Inhoudsscripts en andere extensiepagina's beschikken niet over deze API's. De API's zijn dus alleen beschikbaar gedurende de levensduur van het DevTools-venster.

Er zijn ook enkele DevTools API's die nog experimenteel zijn. Raadpleeg chrome.experimental.* API's voor de lijst met experimentele API's en richtlijnen voor het gebruik ervan.

DevTools UI-elementen: panelen en zijbalkvensters

Naast de gebruikelijke UI-elementen van de extensie, zoals browseracties, contextmenu's en pop-ups, kan een DevTools-extensie UI-elementen toevoegen aan het DevTools-venster:

  • Een paneel is een tabblad op het hoogste niveau, net als de panelen Elementen, Bronnen en Netwerk.
  • Een zijbalkvenster presenteert een aanvullende gebruikersinterface met betrekking tot een paneel. De deelvensters Stijlen, Berekende stijlen en Gebeurtenislisteners in het paneel Elementen zijn voorbeelden van zijbalkvensters. (Houd er rekening mee dat het uiterlijk van de zijbalkvensters mogelijk niet overeenkomt met de afbeelding, afhankelijk van de versie van Chrome die u gebruikt en waar het DevTools-venster is gekoppeld.)

DevTools-venster met het paneel Elementen en het zijbalkpaneel Stijlen.

Elk paneel is een eigen HTML-bestand, dat andere bronnen kan bevatten (JavaScript, CSS, afbeeldingen, enzovoort). Het maken van een basispaneel ziet er als volgt uit:

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

JavaScript dat wordt uitgevoerd in een paneel of zijbalkvenster heeft toegang tot dezelfde API's als de DevTools-pagina.

Het maken van een basiszijbalkvenster voor het paneel Elementen ziet er als volgt uit:

chrome.devtools.panels.elements.createSidebarPane("My Sidebar",
    function(sidebar) {
        // sidebar initialization code here
        sidebar.setObject({ some_data: "Some data to show" });
});

Er zijn verschillende manieren om inhoud in een zijbalkvenster weer te geven:

  • HTML-inhoud. Roep setPage aan om een ​​HTML-pagina op te geven die in het deelvenster moet worden weergegeven.
  • JSON-gegevens. Geef een JSON-object door aan setObject .
  • JavaScript-expressie. Geef een expressie door aan setExpression . DevTools evalueert de expressie in de context van de geïnspecteerde pagina en geeft de geretourneerde waarde weer.

Voor zowel setObject als setExpression wordt in het deelvenster de waarde weergegeven zoals deze zou verschijnen in de DevTools-console. setExpression kunt u echter DOM-elementen en willekeurige JavaScript-objecten weergeven, terwijl setObject alleen JSON-objecten ondersteunt.

Communiceren tussen uitbreidingscomponenten

In de volgende secties worden enkele typische scenario's beschreven voor de communicatie tussen de verschillende componenten van een DevTools-extensie.

Een inhoudsscript injecteren

De DevTools-pagina kan tabs.executeScript niet rechtstreeks aanroepen. Om een ​​inhoudsscript vanaf de DevTools-pagina te injecteren, moet u de ID van het geïnspecteerde venstertabblad ophalen met behulp van de eigenschap inspectedWindow.tabId en een bericht naar de achtergrondpagina sturen. Roep vanaf de achtergrondpagina tabs.executeScript aan om het script te injecteren.

De volgende codefragmenten laten zien hoe u een inhoudsscript kunt injecteren met executeScript .

// DevTools page -- devtools.js
// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

backgroundPageConnection.onMessage.addListener(function (message) {
    // Handle responses from the background page, if any
});

// Relay the tab ID to the background page
chrome.runtime.sendMessage({
    tabId: chrome.devtools.inspectedWindow.tabId,
    scriptToInject: "content_script.js"
});

Code voor de achtergrondpagina:

// Background page -- background.js
chrome.runtime.onConnect.addListener(function(devToolsConnection) {
    // assign the listener function to a variable so we can remove it later
    var devToolsListener = function(message, sender, sendResponse) {
        // Inject a content script into the identified tab
        chrome.tabs.executeScript(message.tabId,
            { file: message.scriptToInject });
    }
    // add the listener
    devToolsConnection.onMessage.addListener(devToolsListener);

    devToolsConnection.onDisconnect.addListener(function() {
         devToolsConnection.onMessage.removeListener(devToolsListener);
    });
});

JavaScript evalueren in het geïnspecteerde venster

U kunt de methode inspectedWindow.eval gebruiken om JavaScript-code uit te voeren in de context van de geïnspecteerde pagina. U kunt de eval methode oproepen vanaf een DevTools-pagina, -paneel of zijbalkvenster.

Standaard wordt de expressie geëvalueerd in de context van het hoofdframe van de pagina. Nu bent u wellicht bekend met de functies van de opdrachtregel-API van DevTools, zoals elementinspectie ( inspect(elem) ), functies inbreken ( debug(fn) ), kopiëren naar klembord ( copy() ) en meer. inspectedWindow.eval() gebruikt dezelfde scriptuitvoeringscontext en -opties als de code die is getypt op de DevTools-console, waardoor toegang tot deze API's binnen de eval mogelijk wordt gemaakt. SOAK gebruikt het bijvoorbeeld voor het inspecteren van een element:

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

U kunt ook de optie useContentScriptContext: true voor inspectedWindow.eval() gebruiken om de expressie in dezelfde context te evalueren als de inhoudsscripts. Door eval aan te roepen met useContentScriptContext: true wordt geen contentscriptcontext gemaakt , dus u moet een contextscript laden voordat u eval aanroept, door executeScript aan te roepen of door een contentscript op te geven in het bestand manifest.json .

Zodra de contextscriptcontext bestaat, kunt u deze optie gebruiken om aanvullende inhoudscripts te injecteren.

De eval is krachtig als deze in de juiste context wordt gebruikt, maar gevaarlijk als deze op de verkeerde manier wordt gebruikt. Gebruik de methode tabs.executeScript als u geen toegang nodig heeft tot de JavaScript-context van de geïnspecteerde pagina. Zie inspectedWindow voor gedetailleerde waarschuwingen en een vergelijking van de twee methoden.

Het geselecteerde element doorgeven aan een inhoudsscript

Het inhoudsscript heeft geen directe toegang tot het huidige geselecteerde element. Elke code die u uitvoert met inspectedWindow.eval heeft echter toegang tot de DevTools-console en opdrachtregel-API's. In geëvalueerde code kunt u bijvoorbeeld $0 gebruiken om toegang te krijgen tot het geselecteerde element.

Het geselecteerde element doorgeven aan een inhoudsscript:

  • Maak een methode in het inhoudsscript die het geselecteerde element als argument gebruikt.
  • Roep de methode aan vanaf de DevTools-pagina met behulp van inspectedWindow.eval met de optie useContentScriptContext: true .

De code in uw inhoudsscript kan er ongeveer zo uitzien:

function setSelectedElement(el) {
    // do something with the selected element
}

Roep de methode als volgt aan vanaf de DevTools-pagina:

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

De optie useContentScriptContext: true geeft aan dat de expressie moet worden geëvalueerd in dezelfde context als de inhoudsscripts, zodat deze toegang krijgt tot de setSelectedElement methode.

window van een referentiepaneel verkrijgen

Om postMessage vanuit een devtools-paneel te posten, hebt u een verwijzing naar het window nodig. Haal het iframe-venster van een paneel op via de gebeurtenishandler panel.onShown :

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

Berichten van inhoudsscripts naar de DevTools-pagina

Berichten tussen de DevTools-pagina en inhoudsscripts zijn indirect, via de achtergrondpagina.

Wanneer u een bericht naar een inhoudsscript verzendt, kan de achtergrondpagina de methode tabs.sendMessage gebruiken, die een bericht naar de inhoudsscripts op een specifiek tabblad stuurt, zoals weergegeven in Een inhoudsscript injecteren .

Wanneer u een bericht verzendt vanuit een inhoudsscript, bestaat er geen kant-en-klare methode om een ​​bericht af te leveren op de juiste DevTools-pagina-instantie die aan het huidige tabblad is gekoppeld. Als tijdelijke oplossing kunt u de DevTools-pagina een langdurige verbinding met de achtergrondpagina laten maken, en de achtergrondpagina een overzicht van tabblad-ID's naar verbindingen laten bijhouden, zodat elk bericht naar de juiste verbinding kan worden doorgestuurd.

// background.js
var connections = {};

chrome.runtime.onConnect.addListener(function (port) {

    var extensionListener = function (message, sender, sendResponse) {

        // The original connection event doesn't include the tab ID of the
        // DevTools page, so we need to send it explicitly.
        if (message.name == "init") {
          connections[message.tabId] = port;
          return;
        }

    // other message handling
    }

    // Listen to messages sent from the DevTools page
    port.onMessage.addListener(extensionListener);

    port.onDisconnect.addListener(function(port) {
        port.onMessage.removeListener(extensionListener);

        var tabs = Object.keys(connections);
        for (var i=0, len=tabs.length; i < len; i++) {
          if (connections[tabs[i]] == port) {
            delete connections[tabs[i]]
            break;
          }
        }
    });
});

// Receive message from content script and relay to the devTools page for the
// current tab
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    // Messages from content scripts should have sender.tab set
    if (sender.tab) {
      var tabId = sender.tab.id;
      if (tabId in connections) {
        connections[tabId].postMessage(request);
      } else {
        console.log("Tab not found in connection list.");
      }
    } else {
      console.log("sender.tab not defined.");
    }
    return true;
});

De DevTools-pagina (of paneel- of zijbalkvenster) brengt de verbinding als volgt tot stand:

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "panel"
});

backgroundPageConnection.postMessage({
    name: 'init',
    tabId: chrome.devtools.inspectedWindow.tabId
});

Berichten van geïnjecteerde scripts naar de DevTools-pagina

Hoewel de bovenstaande oplossing werkt voor inhoudsscripts, vereist code die rechtstreeks in de pagina wordt geïnjecteerd (bijvoorbeeld door het toevoegen van een <script> -tag of via inspectedWindow.eval ) een andere strategie. In deze context zal runtime.sendMessage geen berichten doorgeven aan het achtergrondscript zoals verwacht.

Als tijdelijke oplossing kunt u uw geïnjecteerde script combineren met een inhoudsscript dat als tussenpersoon fungeert. Om berichten door te geven aan het inhoudsscript, kunt u de window.postMessage API gebruiken. Hier is een voorbeeld, uitgaande van het achtergrondscript uit de vorige sectie:

// 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
  if (typeof message !== 'object' || message === null ||
      !message.source === 'my-devtools-extension') {
    return;
  }

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

Uw bericht stroomt nu van het geïnjecteerde script naar het inhoudsscript, naar het achtergrondscript en uiteindelijk naar de DevTools-pagina.

U kunt hier ook twee alternatieve technieken voor het doorgeven van berichten overwegen.

Detecteren wanneer DevTools wordt geopend en gesloten

Als uw extensie moet bijhouden of het DevTools-venster geopend is, kunt u een onConnect- listener aan de achtergrondpagina toevoegen en connect aanroepen vanaf de DevTools-pagina. Omdat op elk tabblad een eigen DevTools-venster geopend kan zijn, kunt u meerdere connect-gebeurtenissen ontvangen. Om bij te houden of er een DevTools-venster geopend is, moet u de verbindings- en verbindingsgebeurtenissen tellen, zoals hieronder weergegeven:

// 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.");
          }
      });
    }
});

De DevTools-pagina maakt een verbinding als deze:

// devtools.js

// Create a connection to the background page
var backgroundPageConnection = chrome.runtime.connect({
    name: "devtools-page"
});

Voorbeelden van DevTools-extensies

Blader door de bron van deze voorbeelden van DevTools-extensies:

  • Polymer Devtools Extensie - gebruikt veel helpers die op de hostpagina draaien om de DOM/JS-status op te vragen en terug te sturen naar het aangepaste paneel.
  • React DevTools-extensie - Gebruikt een submodule van Blink om DevTools UI-componenten opnieuw te gebruiken.
  • Ember Inspector - Gedeelde extensiekern met adapters voor zowel Chrome als Firefox.
  • Coquette-inspect - Een schone, op React gebaseerde extensie met een foutopsporingsagent die in de hostpagina is geïnjecteerd.
  • onze DevTools Extension Gallery en Sample Extensions hebben meer waardevolle apps om te installeren, uit te proberen en van te leren.

Meer informatie

Zie chrome.* API's en web-API's voor informatie over de standaard-API's die extensies kunnen gebruiken.

Geef ons feedback! Uw opmerkingen en suggesties helpen ons de API's te verbeteren.

Voorbeelden

Voorbeelden van het gebruik van DevTools API's vindt u in Samples .