Estensione di DevTools

Panoramica

Un'estensione DevTools aggiunge funzionalità a Chrome DevTools. Può aggiungere nuovi riquadri dell'interfaccia utente e barre laterali, interagire con la pagina ispezionata, ottenere informazioni sulle richieste di rete e altro ancora. Visualizza le estensioni DevTools in primo piano. Le estensioni DevTools hanno accesso a un set aggiuntivo di API di estensioni specifiche per DevTools:

Un'estensione DevTools è strutturata come qualsiasi altra estensione: può avere una pagina in background, script di contenuti e altri elementi. Inoltre, ogni estensione DevTools ha una pagina DevTools che ha accesso alle API DevTools.

Diagramma dell'architettura che mostra la pagina DevTools che comunica con la finestra ispezionata e la pagina in background. La pagina in background viene mostrata mentre comunica con gli script di contenuti e accede alle API delle estensioni.
       La pagina DevTools ha accesso alle API DevTools, ad esempio creando riquadri.

Pagina DevTools

Un'istanza della pagina DevTools dell'estensione viene creata ogni volta che si apre una finestra DevTools. La pagina DevTools esiste per tutta la durata della finestra DevTools. La pagina DevTools ha accesso alle API DevTools e a un insieme limitato di API di estensioni. In particolare, la pagina DevTools può:

  • Creare e interagire con i riquadri utilizzando le API di devtools.panels.
  • Ottieni informazioni sulla finestra ispezionata e valuta il codice nella finestra ispezionata utilizzando le API devtools.inspectedWindow.
  • Ottieni informazioni sulle richieste di rete utilizzando le API di devtools.network.

La pagina DevTools non può utilizzare direttamente la maggior parte delle API delle estensioni. Ha accesso allo stesso sottoinsieme delle API extension e runtime a cui ha accesso uno script di contenuti. Come uno script di contenuti, una pagina DevTools può comunicare con la pagina in background tramite la trasmissione di messaggi. Per un esempio, consulta la sezione Inserimento di uno script di contenuti.

Creazione di un'estensione DevTools

Per creare una pagina DevTools per l'estensione, aggiungi il campo devtools_page nel manifest dell'estensione:

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

Viene creata un'istanza del devtools_page specificata nel manifest dell'estensione per ogni finestra di DevTools aperta. La pagina potrebbe aggiungere altre pagine di estensioni come riquadri e barre laterali alla finestra di DevTools utilizzando l'API devtools.panels.

I moduli dell'API chrome.devtools.* sono disponibili solo per le pagine caricate all'interno della finestra DevTools. Gli script di contenuti e le altre pagine di estensioni non dispongono di queste API. Pertanto, le API sono disponibili solo per tutta la durata della finestra DevTools.

Esistono anche alcune API DevTools ancora in fase sperimentale. Consulta chrome.experimental.* API per l'elenco delle API sperimentali e le linee guida su come utilizzarle.

Elementi dell'interfaccia utente di DevTools: riquadri e riquadri della barra laterale

Oltre ai normali elementi dell'interfaccia utente delle estensioni, ad esempio azioni del browser, menu contestuali e popup, un'estensione DevTools può aggiungere elementi dell'interfaccia utente alla finestra DevTools:

  • Un riquadro è una scheda di primo livello, come i riquadri Elementi, Origini e Rete.
  • Un riquadro della barra laterale presenta un'interfaccia utente supplementare relativa a un riquadro. I riquadri Stili, Stili elaborati e Listener di eventi nel riquadro Elementi sono esempi di riquadri della barra laterale. Tieni presente che l'aspetto dei riquadri della barra laterale potrebbe non corrispondere all'immagine, a seconda della versione di Chrome in uso e del punto in cui la finestra DevTools è agganciata.

Finestra DevTools in cui viene mostrato il riquadro Elementi e il riquadro della barra laterale Stili.

Ogni riquadro è un file HTML a sé stante, che può includere altre risorse (JavaScript, CSS, immagini e così via). La creazione di un riquadro di base ha il seguente aspetto:

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

JavaScript eseguito in un riquadro o in un riquadro della barra laterale ha accesso alle stesse API della pagina DevTools.

La creazione di un riquadro della barra laterale di base per il riquadro Elementi ha il seguente aspetto:

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

Esistono diversi modi per visualizzare i contenuti in un riquadro della barra laterale:

  • Contenuti HTML. Chiama setPage per specificare una pagina HTML da visualizzare nel riquadro.
  • Dati JSON. Passa un oggetto JSON a setObject.
  • espressione JavaScript. Passa un'espressione a setExpression. DevTools valuta l'espressione nel contesto della pagina ispezionata e mostra il valore restituito.

Per setObject e setExpression, il riquadro mostra il valore così come apparirebbe nella console di DevTools. Tuttavia, setExpression consente di visualizzare elementi DOM e oggetti JavaScript arbitrari, mentre setObject supporta solo oggetti JSON.

Comunicazione tra i componenti delle estensioni

Le seguenti sezioni descrivono alcuni scenari tipici di comunicazione tra i diversi componenti di un'estensione DevTools.

Inserimento di uno script di contenuti

La pagina DevTools non può chiamare direttamente tabs.executeScript. Per inserire uno script di contenuti dalla pagina DevTools, devi recuperare l'ID della scheda della finestra ispezionata utilizzando la proprietà inspectedWindow.tabId e inviare un messaggio alla pagina in background. Dalla pagina di sfondo, chiama tabs.executeScript per inserire lo script.

I seguenti snippet di codice mostrano come inserire uno script di contenuti utilizzando 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"
});

Codice per la pagina di sfondo:

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

Valutazione di JavaScript nella finestra ispezionata

Puoi utilizzare il metodo inspectedWindow.eval per eseguire codice JavaScript nel contesto della pagina ispezionata. Puoi richiamare il metodo eval da una pagina, un riquadro o un riquadro della barra laterale di DevTools.

Per impostazione predefinita, l'espressione viene valutata nel contesto del frame principale della pagina. A questo punto potresti avere familiarità con le funzionalità dell'API a riga di comando di DevTools, come l'ispezione degli elementi (inspect(elem)), l'interruzione delle funzioni (debug(fn)), la copia negli appunti (copy()) e altro ancora. inspectedWindow.eval() utilizza lo stesso contesto di esecuzione degli script e le stesse opzioni del codice digitato nella console di DevTools, che consente l'accesso a queste API durante la valutazione. Ad esempio, SOAK lo utilizza per ispezionare un elemento:

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

In alternativa, utilizza l'opzione useContentScriptContext: true per inspectedWindow.eval() per valutare l'espressione nello stesso contesto degli script dei contenuti. La chiamata a eval con useContentScriptContext: true non crea un contesto di script di contenuti, quindi devi caricare uno script di contesto prima di chiamare eval. Puoi chiamare il numero executeScript o specificare uno script di contenuti nel file manifest.json.

Una volta creato il contesto dello script di contesto, puoi utilizzare questa opzione per inserire script di contenuti aggiuntivi.

Il metodo eval è efficace se utilizzato nel contesto giusto e pericoloso se utilizzato in modo non appropriato. Utilizza il metodo tabs.executeScript se non hai bisogno di accedere al contesto JavaScript della pagina ispezionata. Per avvertenze dettagliate e un confronto tra i due metodi, consulta la pagina inspectedWindow.

Trasmettere l'elemento selezionato a uno script di contenuti

Lo script dei contenuti non ha accesso diretto all'elemento selezionato corrente. Tuttavia, qualsiasi codice che esegui utilizzando inspectedWindow.eval ha accesso alla console DevTools e alle API a riga di comando. Ad esempio, nel codice valutato puoi utilizzare $0 per accedere all'elemento selezionato.

Per passare l'elemento selezionato a uno script di contenuti:

  • Crea un metodo nello script dei contenuti che prenda l'elemento selezionato come argomento.
  • Chiama il metodo dalla pagina DevTools utilizzando inspectedWindow.eval con l'opzione useContentScriptContext: true.

Il codice nello script dei contenuti potrebbe avere il seguente aspetto:

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

Richiama il metodo dalla pagina DevTools in questo modo:

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

L'opzione useContentScriptContext: true specifica che l'espressione deve essere valutata nello stesso contesto degli script di contenuti, in modo che possa accedere al metodo setSelectedElement.

Recupero dei window di un riquadro di riferimento

Per postMessage da un riquadro devtools, è necessario un riferimento al relativo oggetto window. Ottieni la finestra iframe di un riquadro dal gestore di eventi panel.onShown:

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

Messaggistica dagli script di contenuti alla pagina DevTools

I messaggi tra la pagina DevTools e gli script dei contenuti sono indiretti, tramite la pagina in background.

Quando invii un messaggio a uno script di contenuti, la pagina in background può utilizzare il metodo tabs.sendMessage, che indirizza un messaggio agli script di contenuti in una scheda specifica, come illustrato in Inserimento di uno script di contenuti.

Quando invii un messaggio da uno script di contenuti, non esiste un metodo pronto all'uso per consegnare un messaggio all'istanza della pagina DevTools corretta associata alla scheda corrente. Come soluzione alternativa, puoi fare in modo che la pagina DevTools stabilisca una connessione di lunga durata con la pagina in background e che quest'ultima mantenga una mappa degli ID scheda alle connessioni, in modo che possa indirizzare ogni messaggio alla connessione corretta.

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

La pagina DevTools (oppure il riquadro o il riquadro della barra laterale) stabilisce la connessione in questo modo:

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

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

Messaggi dagli script inseriti nella pagina DevTools

Anche se la soluzione descritta in precedenza funziona con gli script di contenuti, il codice inserito direttamente nella pagina (ad es. tramite l'aggiunta di un tag <script> o tramite inspectedWindow.eval) richiede una strategia diversa. In questo contesto, runtime.sendMessage non trasmetterà messaggi allo script in background come previsto.

Come soluzione alternativa, puoi combinare lo script inserito con uno script di contenuti che funge da intermediario. Per trasmettere messaggi allo script dei contenuti, puoi utilizzare l'API window.postMessage. Ecco un esempio, supponendo che lo script in background della sezione precedente:

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

Il tuo messaggio passerà dallo script inserito, allo script dei contenuti, allo script in background e infine alla pagina DevTools.

Puoi anche prendere in considerazione due tecniche alternative per la trasmissione dei messaggi.

Rilevamento dell'apertura e della chiusura di DevTools

Se l'estensione deve monitorare se la finestra DevTools è aperta, puoi aggiungere un ascolto onConnect alla pagina in background e chiamare connect dalla pagina DevTools. Poiché ogni scheda può avere la propria finestra DevTools aperta, potresti ricevere più eventi di connessione. Per monitorare se è aperta una finestra di DevTools, devi conteggiare gli eventi di connessione e disconnessione come mostrato di seguito:

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

La pagina DevTools crea una connessione come questa:

// devtools.js

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

Esempi di estensioni DevTools

Sfoglia l'origine di questi esempi di estensioni DevTools:

Maggiori informazioni

Per informazioni sulle API standard utilizzabili dalle estensioni, vedi chrome.* API e API web.

Inviaci il tuo feedback. I tuoi commenti e suggerimenti ci aiutano a migliorare le API.

Esempi

Puoi trovare esempi che utilizzano le API DevTools in Samples.