Estender o DevTools

Visão geral

Uma extensão do DevTools adiciona funcionalidade ao Chrome DevTools. Ele pode adicionar novos painéis de interface barras laterais, interaja com a página inspecionada, obtenha informações sobre solicitações de rede e muito mais. Visualizar extensões do DevTools em destaque. As extensões do DevTools têm acesso a um conjunto adicional de APIs de extensão específicas do DevTools:

Uma extensão do DevTools é estruturada como qualquer outra extensão: ela pode ter uma página de fundo, conteúdo scripts e outros itens. Além disso, cada extensão do DevTools tem uma página do DevTools que dá acesso às APIs do DevTools.

Diagrama de arquitetura mostrando a página do DevTools se comunicando com o
       janela inspecionada e a página de plano de fundo. A página de plano de fundo é mostrada
       comunicação com scripts de conteúdo e acesso a APIs de extensão.
       A página do DevTools tem acesso às APIs do DevTools, por exemplo, ao criar painéis.

Página do DevTools

Uma instância da página DevTools da extensão é criada sempre que uma janela do DevTools é aberta. A A página do DevTools existe durante todo o ciclo de vida da janela do DevTools. A página do DevTools tem acesso ao APIs do DevTools e um conjunto limitado de APIs de extensão. Especificamente, a página do DevTools pode:

  • Crie e interaja com painéis usando as APIs devtools.panels.
  • Receba informações sobre a janela inspecionada e avalie o código na janela inspecionada usando o devtools.inspectedWindow APIs.
  • Receba informações sobre solicitações de rede usando as APIs devtools.network.

A página do DevTools não pode usar a maioria das APIs de extensão diretamente. Ele tem acesso ao mesmo subconjunto das APIs extension e runtime a que um script de conteúdo tem acesso. Marcar um conteúdo com "Gostei" uma página do DevTools pode se comunicar com a página em segundo plano usando o Message Passing. Para um exemplo, consulte Como injetar um script de conteúdo.

Como criar uma extensão do DevTools

Para criar uma página do DevTools para sua extensão, adicione o campo devtools_page à extensão. manifesto do app:

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

Uma instância da devtools_page especificada no manifesto da extensão é criada para cada A janela do DevTools foi aberta. A página pode adicionar outras páginas de extensão como painéis e barras laterais à Janela do DevTools usando a API devtools.panels.

Os módulos da API chrome.devtools.* estão disponíveis apenas para as páginas carregadas no DevTools janela. Scripts de conteúdo e outras páginas de extensão não têm essas APIs. Assim, as APIs são disponível apenas durante o ciclo de vida da janela DevTools.

Há também algumas APIs DevTools que ainda são experimentais. Consulte chrome.experimental.* APIs para a lista de APIs experimentais e orientações sobre como usá-las.

Elementos da interface do DevTools: painéis e painéis da barra lateral

Além dos elementos de interface de extensão usuais, como ações do navegador, menus de contexto e pop-ups, uma A extensão do DevTools pode adicionar elementos da interface à janela do DevTools:

  • Um painel é uma guia de nível superior, como os painéis "Elementos", "Origens" e "Rede".
  • Um painel da barra lateral apresenta a interface complementar relacionada a um painel. Os estilos, estilos computados e Os painéis de Listeners de eventos no painel Elementos são exemplos de painéis de barra lateral. (Observe que o a aparência dos painéis da barra lateral pode não corresponder à imagem, dependendo da versão do Chrome que você está usando e onde a janela do DevTools está ancorada.)

Janela do DevTools mostrando os painéis Elements e Styles da barra lateral.

Cada painel é um arquivo HTML próprio, que pode incluir outros recursos (JavaScript, CSS, imagens e muito A criação de um painel básico é semelhante ao seguinte:

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

O JavaScript executado em um painel ou painel de barra lateral tem acesso às mesmas APIs que a página do DevTools.

A criação de um painel básico de barra lateral para o painel Elementos é semelhante ao seguinte:

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

Há várias maneiras de exibir conteúdo em um painel de barra lateral:

  • Conteúdo HTML. Chame setPage para especificar uma página HTML a ser exibida no painel.
  • dados JSON. Transmita um objeto JSON para setObject.
  • Expressão JavaScript. Transmita uma expressão para setExpression. O DevTools avalia o no contexto da página inspecionada e exibe o valor de retorno.

Para setObject e setExpression, o painel exibe o valor como ele apareceria no Console do DevTools. No entanto, setExpression permite exibir elementos DOM e JavaScript arbitrário. objetos, enquanto setObject oferece suporte apenas a objetos JSON.

Como estabelecer comunicação entre componentes de extensão

As seções a seguir descrevem alguns cenários típicos para a comunicação entre os diferentes componentes de uma extensão do DevTools.

Como injetar um script de conteúdo

A página do DevTools não pode chamar tabs.executeScript diretamente. Para injetar um script de conteúdo de página do DevTools, recupere o ID da guia da janela inspecionada usando o inspectedWindow.tabId e enviar uma mensagem para a página em segundo plano. Na guia página em segundo plano, chame tabs.executeScript para injetar o script.

Os snippets de código a seguir mostram como injetar um script de conteúdo usando 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 para a página de plano de fundo:

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

Como avaliar o JavaScript na janela inspecionada

Você pode usar o método inspectedWindow.eval para executar o código JavaScript no contexto da inspecionada. Você pode invocar o método eval de uma página, um painel ou um painel da barra lateral do DevTools.

Por padrão, a expressão é avaliada no contexto do frame principal da página. É possível Conhecer os recursos da API de linha de comando do DevTools, como a inspeção de elementos. (inspect(elem)), interrupções em funções (debug(fn)), cópia para a área de transferência (copy()) e muito mais. O inspectedWindow.eval() usa o mesmo contexto e opções de execução de script que o código digitado na Console do DevTools, que permite o acesso a essas APIs durante a avaliação. Por exemplo, SOAK o utiliza para inspecionar um elemento:

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

Como alternativa, use a opção useContentScriptContext: true do inspectedWindow.eval() para avaliar a expressão no mesmo contexto que os scripts de conteúdo. Ligando para eval com useContentScriptContext: true não cria um contexto de script de conteúdo, portanto, você deve carregar uma script de contexto antes de chamar eval, chamando executeScript ou especificando um objeto script no arquivo manifest.json.

Quando o contexto do script de contexto existir, será possível usar essa opção para injetar mais conteúdo scripts.

O método eval é eficiente quando usado no contexto certo e perigoso quando usado inadequadamente. Use o método tabs.executeScript se você não precisar de acesso ao Contexto do JavaScript da página inspecionada. Para precauções detalhadas e uma comparação dos dois métodos, consulte inspectedWindow.

Transmitir o elemento selecionado para um script de conteúdo

O script de conteúdo não tem acesso direto ao elemento selecionado no momento. No entanto, qualquer código que você executar usando inspectedWindow.eval tem acesso ao console do DevTools e às APIs de linha de comando. Por exemplo, no código avaliado, é possível usar $0 para acessar o elemento selecionado.

Para transmitir o elemento selecionado a um script de conteúdo:

  • Crie um método no script de conteúdo que use o elemento selecionado como argumento.
  • Chame o método na página do DevTools usando inspectedWindow.eval com o useContentScriptContext: true.

O código no seu script de conteúdo pode ser parecido com este:

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

Invoque o método pela página do DevTools desta forma:

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

A opção useContentScriptContext: true especifica que a expressão precisa ser avaliada no mesmo contexto que os scripts de conteúdo, para que ele possa acessar o método setSelectedElement.

Como receber o window de um painel de referência

Para usar o postMessage em um painel do DevTools, será necessária uma referência ao objeto window dele. Acesse a janela de iframe de um painel no manipulador de eventos panel.onShown:

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

Como enviar mensagens de scripts de conteúdo para a página do DevTools

As mensagens entre a página do DevTools e os scripts de conteúdo são indiretas, pela página em segundo plano.

Ao enviar uma mensagem para um script de conteúdo, a página de plano de fundo pode usar a tabs.sendMessage, que direciona uma mensagem para os scripts de conteúdo em uma guia específica. conforme mostrado em Como injetar um script de conteúdo.

Ao enviar uma mensagem de um script de conteúdo, não há um método pronto para entregar uma mensagem. para a instância correta da página DevTools associada à guia atual. Como solução alternativa, você pode ter a página DevTools estabeleça uma conexão de longa duração com a página de fundo e faça com que a página de plano de fundo mantêm um mapa de IDs de guias para as conexões, para que possa encaminhar cada mensagem para o endereço uma conexão com a Internet.

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

A página do DevTools (ou painel ou painel da barra lateral) estabelece a conexão desta forma:

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

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

Mensagens de scripts injetados para a página do DevTools

Embora a solução acima funcione para scripts de conteúdo, o código injetado diretamente na página (por exemplo, anexar uma tag <script> ou pelo inspectedWindow.eval) requer uma uma estratégia diferente. Nesse contexto, o runtime.sendMessage não vai transmitir mensagens para o o script de segundo plano conforme esperado.

Como solução alternativa, você pode combinar o script injetado com um script de conteúdo que atue como uma intermediário. Para transmitir mensagens ao script de conteúdo, use window.postMessage. API. Aqui está um exemplo, considerando o script de plano de fundo da seção 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);
});

Sua mensagem passará do script injetado para o script de conteúdo, para o segundo plano script e, por fim, para a página DevTools.

Você também pode usar duas técnicas alternativas de transmissão de mensagens aqui.

Detectar quando o DevTools abre e fecha

Caso sua extensão precise rastrear se a janela do DevTools está aberta, adicione um onConnect à página de segundo plano e chame connect na página do DevTools. Como cada guia pode estiver com a própria janela do DevTools aberta, poderá receber vários eventos de conexão. Para acompanhar se há DevTools está aberta, você precisa contar os eventos de conexão e desconexão conforme mostrado abaixo:

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

A página DevTools cria uma conexão como esta:

// devtools.js

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

Exemplos de extensão do DevTools

Procure a fonte desses exemplos de extensão do DevTools:

Mais informações

Para mais informações sobre as APIs padrão que as extensões podem usar, consulte chrome.* APIs e Web APIs.

Envie seu feedback. Seus comentários e sugestões nos ajudam a melhorar as APIs.

Exemplos

Confira exemplos que usam as APIs do DevTools em Amostras (link em inglês).