Estensione di DevTools

Panoramica

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

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

Diagramma dell'architettura che mostra la pagina di DevTools che comunica con la finestra esaminata e la pagina di sfondo. La pagina di sfondo viene mostrata
       mentre comunica con gli script di contenuti e accede alle API di estensioni.
       La pagina DevTools ha accesso alle API DevTools, ad esempio per la creazione di riquadri.

Pagina DevTools

Ogni volta che si apre una finestra di DevTools, viene creata un'istanza della pagina DevTools dell'estensione. 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. Nello specifico, la pagina DevTools può:

  • Crea e interagisci con i riquadri utilizzando le API devtools.panels.
  • Visualizza informazioni sulla finestra ispezionata e valuta il codice al suo interno utilizzando le API devtools.inspectedWindow.
  • Visualizza informazioni sulle richieste di rete utilizzando le API devtools.network.

La pagina DevTools non può utilizzare direttamente la maggior parte delle API di 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 di DevTools può comunicare con la pagina in background utilizzando il passaggio di messaggi. Per un esempio, vedi Eseguire l'iniezione di uno script di contenuti.

Creazione di un'estensione DevTools

Per creare una pagina di 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",
  ...
}

Per ogni finestra di DevTools aperta viene creata un'istanza di devtools_page specificata nel manifest dell'estensione. La pagina può 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 contenuto e altre pagine di estensione non dispongono di queste API. Pertanto, le API sono disponibili solo per tutta la durata della finestra di DevTools.

Esistono anche alcune API DevTools ancora sperimentali. Fai riferimento a 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 soliti elementi dell'interfaccia utente delle estensioni, come azioni del browser, menu contestuali e popup, un'estensione di DevTools può aggiungere elementi dell'interfaccia utente alla finestra di 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 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 della posizione in cui è agganciata la finestra di DevTools.

Finestra di DevTools che mostra il riquadro Elementi e il riquadro della barra laterale Stili.

Ogni riquadro è un file HTML autonomo, che può includere altre risorse (JavaScript, CSS, immagini e così via). La creazione di un riquadro di base è la seguente:

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

Il codice JavaScript eseguito in un riquadro o nel 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.

Sia per setObject che per setExpression, il riquadro mostra il valore visualizzato nella console DevTools. Tuttavia, setExpression consente di visualizzare elementi DOM e oggetti JavaScript arbitrari, mentre setObject supporta solo gli oggetti JSON.

Comunicazione tra i componenti dell'estensione

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

Inserire uno script di contenuti

La pagina DevTools non può chiamare direttamente tabs.executeScript. Per iniettare 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 di sfondo. Dalla pagina di sfondo, chiama tabs.executeScript per iniettare lo script.

I seguenti snippet di codice mostrano come iniettare 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. Ora potresti essere familiare con le funzionalità dell'API a riga di comando di DevTools, come l'ispezione degli elementi (inspect(elem)), l'interruzione nelle funzioni (debug(fn)), la copia negli appunti (copy()) e altro ancora. inspectedWindow.eval() utilizza lo stesso contesto di esecuzione dello script e le stesse opzioni del codice digitato nella console di DevTools, che consente l'accesso a queste API all'interno di eval. 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. L'utilizzo di eval con useContentScriptContext: true non create un contesto dello script di contenuti, quindi devi caricare un script di contesto prima di chiamare eval, chiamando executeScript o specificando uno script di contenuti nel file manifest.json.

Una volta che lo script contestuale è stato creato, puoi utilizzare questa opzione per inserire script di contenuti aggiuntivi.

Il metodo eval è efficace se utilizzato nel contesto giusto e pericoloso se usato in modo improprio. 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 inspectedWindow.

Trasmissione dell'elemento selezionato a uno script di contenuti

Lo script dei contenuti non ha accesso diretto all'elemento attualmente selezionato. Tuttavia, qualsiasi codice eseguito utilizzando inspectedWindow.eval ha accesso alla console di 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 come segue:

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

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

Ottenere il valore window di un pannello di riferimento

Per postMessage da un riquadro devtools, devi avere un riferimento al relativo oggetto window. Recupera 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

La messaggistica tra la pagina di DevTools e gli script dei contenuti è indiretta, tramite la pagina di sfondo.

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

Quando invii un messaggio da uno script di contenuti, non esiste un metodo pronto all'uso per inviare 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 permanente con la pagina di sfondo e che quest'ultima mantenga una mappa degli ID scheda per le connessioni, in modo da poter 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 (o il riquadro del riquadro laterale o del riquadro laterale) stabilisce la connessione nel seguente modo:

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

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

Messaggistica dagli script iniettati alla pagina DevTools

Sebbene la soluzione sopra riportata funzioni per gli script dei contenuti, il codice inserito direttamente nella pagina (ad es. aggiungendo un tag <script> o tramite inspectedWindow.eval) richiede una strategia diversa. In questo contesto, runtime.sendMessage non passerà i messaggi allo script in background come previsto.

Come soluzione alternativa, puoi combinare lo script iniettato con uno script di contenuti che funge da intermediario. Per passare i messaggi allo script dei contenuti, puoi utilizzare l'API window.postMessage. Ecco un esempio, supponendo 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 messaggio passerà dallo script iniettato allo script dei contenuti, allo script di sfondo e infine alla pagina di DevTools.

Puoi anche prendere in considerazione due tecniche alternative di trasmissione dei messaggi qui.

Rilevare l'apertura e la chiusura di DevTools

Se l'estensione deve monitorare se la finestra di DevTools è aperta, puoi aggiungere un ascoltatore onConnect alla pagina in background e chiamare connect dalla pagina di DevTools. Poiché ogni scheda può avere la propria finestra di 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 di DevTools

Sfoglia il codice sorgente di questi esempi di estensioni DevTools:

Ulteriori informazioni

Per informazioni sulle API standard che le estensioni possono utilizzare, consulta 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.