Cómo extender Herramientas para desarrolladores

Descripción general

Una extensión de DevTools agrega funcionalidad a Chrome DevTools. Puede agregar nuevos paneles de IU y las barras laterales, interactuar con la página inspeccionada, obtener información sobre las solicitudes de red y mucho más. Consulta las extensiones de DevTools destacadas. Las extensiones de Herramientas para desarrolladores tienen acceso a un conjunto adicional de APIs de extensión específicas de Herramientas para desarrolladores:

Una extensión de Herramientas para desarrolladores se estructura como cualquier otra extensión: puede tener una página de fondo, contenido secuencias de comandos y otros elementos. Además, cada extensión de DevTools tiene una página de DevTools, que tiene acceso a las APIs de DevTools.

Diagrama de arquitectura que muestra la página de DevTools que se comunica con la ventana inspeccionada y la página en segundo plano. Se muestra la página en segundo plano que se comunica con las secuencias de comandos del contenido y accede a las APIs de la extensión.
       La página de DevTools tiene acceso a las APIs de DevTools, por ejemplo, para crear paneles.

La página de Herramientas para desarrolladores

Cada vez que se abre una ventana de Herramientas para desarrolladores, se crea una instancia de la página de Herramientas para desarrolladores de la extensión. La página de DevTools existe durante el tiempo que se abre la ventana de DevTools. La página de Herramientas para desarrolladores tiene acceso a la APIs de Herramientas para desarrolladores y un conjunto limitado de APIs de extensión. Específicamente, la página de Herramientas para desarrolladores puede hacer lo siguiente:

  • Crea paneles e interactúa con ellos mediante las APIs de devtools.panels.
  • Obtén información sobre la ventana inspeccionada y evalúa el código en la ventana inspeccionada con el APIs de devtools.inspectedWindow.
  • Obtén información sobre las solicitudes de red con las APIs de devtools.network.

La página de DevTools no puede usar la mayoría de las APIs de extensiones directamente. Tiene acceso al mismo subconjunto de las APIs de extension y runtime al que tiene acceso una secuencia de comandos de contenido. Al igual que una secuencia de comandos de contenido, una página de DevTools puede comunicarse con la página en segundo plano mediante el envío de mensajes. Para un Por ejemplo, consulta Cómo insertar una secuencia de comandos de contenido.

Cómo crear una extensión de DevTools

Si deseas crear una página de Herramientas para desarrolladores para tu extensión, agrega el campo devtools_page en la extensión manifest:

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

Se crea una instancia del devtools_page especificado en el manifiesto de tu extensión para cada ventana de DevTools que se abre. La página puede agregar otras páginas de extensión como paneles y barras laterales a la ventana de DevTools con la API de devtools.panels.

Los módulos de la API de chrome.devtools.* solo están disponibles para las páginas cargadas en las Herramientas para desarrolladores en la ventana modal. Las secuencias de comandos de contenido y otras páginas de extensiones no tienen estas APIs. Por lo tanto, las APIs son disponible solo durante el ciclo de vida de la ventana de Herramientas para desarrolladores.

También hay algunas APIs de Herramientas para desarrolladores que aún son experimentales. Consulta chrome.experimental.* las API para obtener la lista de las APIs experimentales y los lineamientos para usarlas.

Elementos de la IU de Herramientas para desarrolladores: paneles y paneles de la barra lateral

Además de los elementos habituales de la IU de la extensión, como las acciones del navegador, los menús contextuales y las ventanas emergentes, una extensión de DevTools puede agregar elementos de la IU a la ventana de DevTools:

  • Un panel es una pestaña de nivel superior, como los paneles Elements, Sources y Network.
  • Un panel lateral presenta una IU complementaria relacionada con un panel. Los estilos, los estilos calculados y Los paneles de los objetos de escucha de eventos del panel Elements son ejemplos de paneles de la barra lateral. (Ten en cuenta que el que la apariencia de los paneles de la barra lateral no coincida con la imagen, según la versión de Chrome usando y dónde está anclada la ventana de Herramientas para desarrolladores).

Ventana de DevTools que muestra el panel Elements y el panel lateral Styles.

Cada panel es su propio archivo HTML, que puede incluir otros recursos (JavaScript, CSS, imágenes, etc.). La creación de un panel básico se ve de la siguiente manera:

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

JavaScript ejecutado en un panel o en un panel de la barra lateral tiene acceso a las mismas APIs que la página de Herramientas para desarrolladores.

La creación de un panel básico de barra lateral para el panel Elementos se verá de la siguiente manera:

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

Hay varias formas de mostrar contenido en un panel de la barra lateral:

  • Contenido HTML. Llama a setPage para especificar una página HTML que se mostrará en el panel.
  • Datos JSON Pasa un objeto JSON a setObject.
  • Es una expresión de JavaScript. Pasa una expresión a setExpression. DevTools evalúa la expresión en el contexto de la página inspeccionada y muestra el valor que se devuelve.

Tanto para setObject como para setExpression, el panel muestra el valor tal como aparecería en Consola de Herramientas para desarrolladores. Sin embargo, setExpression te permite mostrar elementos DOM y JavaScript arbitrario objetos, mientras que setObject solo admite objetos JSON.

Cómo establecer comunicaciones entre los componentes de una extensión

Las siguientes secciones describen algunas situaciones típicas de comunicación entre los diferentes componentes de una extensión de Herramientas para desarrolladores.

Cómo insertar un guion de contenido

La página de Herramientas para desarrolladores no puede llamar a tabs.executeScript directamente. Para insertar una secuencia de comandos de contenido desde página de Herramientas para desarrolladores, debes recuperar el ID de la pestaña de la ventana inspeccionada usando el inspectedWindow.tabId y envía un mensaje a la página en segundo plano. Desde la página en segundo plano, llama a tabs.executeScript para insertar la secuencia de comandos.

En los siguientes fragmentos de código, se muestra cómo insertar una secuencia de comandos de contenido con 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"
});

Código de la página en segundo plano:

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

Cómo evaluar JavaScript en la ventana inspeccionada

Puedes usar el método inspectedWindow.eval para ejecutar código JavaScript en el contexto de la página inspeccionada. Puedes invocar el método eval desde una página, un panel o un panel de la barra lateral de Herramientas para desarrolladores.

De forma predeterminada, la expresión se evalúa en el contexto del marco principal de la página. Ahora, puedes Familiarizarte con las funciones de la API de línea de comandos de Herramientas para desarrolladores, como la inspección de elementos (inspect(elem)), rompiendo funciones (debug(fn)), copiar en el portapapeles (copy()) y mucho más. inspectedWindow.eval() usa las mismas opciones y contexto de ejecución de secuencia de comandos que el código escrito en el La consola de Herramientas para desarrolladores, que permite el acceso a estas APIs dentro de la evaluación. Por ejemplo, SOAK lo usa para inspeccionar un elemento:

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

Como alternativa, usa la opción useContentScriptContext: true para inspectedWindow.eval() para evaluar la expresión en el mismo contexto que las secuencias de comandos de contenido. Llamando a eval con useContentScriptContext: true no crea un contexto de secuencia de comandos de contenido, por lo que debes cargar un secuencia de comandos de contexto antes de llamar a eval, ya sea llamando a executeScript o especificando un contenido en el archivo manifest.json.

Una vez que exista el contexto de la secuencia de comandos de contexto, puedes usar esta opción para insertar secuencias de comandos de contenido adicionales.

El método eval es potente cuando se usa en el contexto correcto y peligroso cuando se usa de forma inadecuada. Usa el método tabs.executeScript si no necesitas acceso a la Contexto de JavaScript de la página inspeccionada. Para precauciones detalladas y una comparación de los dos métodos, consulta inspectedWindow.

Pasar el elemento seleccionado a una secuencia de comandos de contenido

La secuencia de comandos de contenido no tiene acceso directo al elemento seleccionado actualmente. Sin embargo, cualquier código que ejecutes con inspectedWindow.eval tiene acceso a la consola de DevTools y a las APIs de línea de comandos. Por ejemplo, en el código evaluado, puedes usar $0 para acceder al elemento seleccionado.

Para pasar el elemento seleccionado a una secuencia de comandos de contenido, haz lo siguiente:

  • Crea un método en la secuencia de comandos de contenido que tome el elemento seleccionado como argumento.
  • Llama al método desde la página de Herramientas para desarrolladores usando inspectedWindow.eval con el comando useContentScriptContext: true opción.

El código de tu secuencia de comandos de contenido podría verse de la siguiente manera:

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

Invoca el método desde la página de DevTools de la siguiente manera:

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

La opción useContentScriptContext: true especifica que la expresión se debe evaluar en el mismo contexto que las secuencias de comandos de contenido para que pueda acceder al método setSelectedElement.

Cómo obtener el window de un panel de referencia

Para postMessage desde un panel de Herramientas para desarrolladores, necesitarás una referencia a su objeto window. Obtén la ventana de iframe de un panel desde el controlador de eventos panel.onShown:

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

Mensajes de las secuencias de comandos de contenido a la página de Herramientas para desarrolladores

La mensajería entre la página de Herramientas para desarrolladores y las secuencias de comandos de contenido es indirecta, a través de la página en segundo plano.

Cuando envías un mensaje a una secuencia de comandos de contenido, la página en segundo plano puede usar el elemento tabs.sendMessage, que dirige un mensaje a las secuencias de comandos de contenido de una pestaña específica como se muestra en Cómo insertar una secuencia de comandos de contenido.

Cuando se envía un mensaje desde una secuencia de comandos de contenido, no hay un método listo para enviar un mensaje a la instancia correcta de la página de DevTools asociada con la pestaña actual. Como solución alternativa, puedes tener la página de Herramientas para desarrolladores establezca una conexión de larga duración con la página en segundo plano y tendrá la la página en segundo plano mantienen un mapa de los IDs de las pestañas a las conexiones, para que se pueda enrutar cada mensaje al conexión.

// 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 página de DevTools (o el panel o panel lateral) establece la conexión de la siguiente manera:

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

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

Mensajes de secuencias de comandos insertadas a la página de DevTools

Si bien la solución anterior funciona para las secuencias de comandos de contenido, el código que se incorpora directamente en la página (p.ej., agregando una etiqueta <script> o inspectedWindow.eval) requiere un estrategia diferente. En este contexto, runtime.sendMessage no pasará mensajes a la secuencia de comandos en segundo plano como se espera.

Como solución alternativa, puede combinar la secuencia de comandos insertada con una secuencia de comandos de contenido que actúe como una intermediario. Para pasar mensajes a la secuencia de comandos de contenido, puedes usar window.postMessage. API de gcloud. Este es un ejemplo, en el que se supone que se usa la secuencia de comandos en segundo plano de la sección anterior:

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

Tu mensaje ahora fluirá de la secuencia de comandos insertada a la secuencia de comandos de contenido, a la secuencia de comandos en segundo plano y, por último, a la página de DevTools.

También puedes considerar dos técnicas alternativas de transmisión de mensajes aquí.

Cómo detectar cuándo se abre y se cierra Herramientas para desarrolladores

Si tu extensión necesita hacer un seguimiento de si la ventana de DevTools está abierta, puedes agregar un objeto de escucha onConnect a la página en segundo plano y llamar a connect desde la página de DevTools. Como cada pestaña puede tener su propia ventana de DevTools abierta, es posible que recibas varios eventos de conexión. Para hacer un seguimiento de La ventana de Herramientas para desarrolladores está abierta. Debes contar los eventos de conexión y desconexión, como se muestra a continuación:

// 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 página de Herramientas para desarrolladores crea una conexión como la siguiente:

// devtools.js

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

Ejemplos de extensión de Herramientas para desarrolladores

Explora la fuente de estos ejemplos de extensiones de DevTools:

Más información

Para obtener información sobre las APIs estándar que pueden usar las extensiones, consulta chrome.* APIs y la Web APIs.

Envíanos tus comentarios. Tus comentarios y sugerencias nos ayudan a mejorar las APIs.

Ejemplos

Puedes encontrar ejemplos que usan las APIs de Herramientas para desarrolladores en Muestras.