DevTools 확장

개요

DevTools 확장 프로그램은 Chrome DevTools에 기능을 추가합니다. 새 UI 패널 및 사이드바를 추가하고, 검사된 페이지와 상호작용하고, 네트워크 요청에 관한 정보를 가져오는 등의 작업을 할 수 있습니다. 추천 DevTools 확장 프로그램을 확인하세요. DevTools 확장 프로그램을 사용하면 DevTools 관련 확장 프로그램 API에 추가로 액세스할 수 있습니다.

DevTools 확장 프로그램은 다른 확장 프로그램과 마찬가지로 백그라운드 페이지, 콘텐츠 스크립트, 기타 항목을 포함할 수 있습니다. 또한 각 DevTools 확장 프로그램에는 DevTools API에 액세스할 수 있는 DevTools 페이지가 있습니다.

검사된 창 및 백그라운드 페이지와 통신하는 DevTools 페이지를 보여주는 아키텍처 다이어그램 콘텐츠 스크립트와 통신하고 확장 프로그램 API에 액세스하는 백그라운드 페이지가 표시됩니다.
       DevTools 페이지에서는 DevTools API에 액세스할 수 있습니다(예: 패널 만들기).

DevTools 페이지

DevTools 창이 열릴 때마다 확장 프로그램의 DevTools 페이지 인스턴스가 생성됩니다. DevTools 페이지는 DevTools 창의 수명 기간 동안 존재합니다. DevTools 페이지에서는 DevTools API 및 제한된 확장 API 집합에 액세스할 수 있습니다. 특히 DevTools 페이지에서는 다음 작업을 할 수 있습니다.

  • devtools.panels API를 사용하여 패널을 만들고 상호작용합니다.
  • devtools.inspectedWindow API를 사용하여 검사된 창에 관한 정보를 가져오고 검사된 창의 코드를 평가합니다.
  • devtools.network API를 사용하여 네트워크 요청에 관한 정보를 가져옵니다.

DevTools 페이지는 대부분의 확장 프로그램 API를 직접 사용할 수 없습니다. 콘텐츠 스크립트가 액세스할 수 있는 extensionruntime API의 동일한 하위 집합에 액세스할 수 있습니다. 콘텐츠 스크립트와 마찬가지로 DevTools 페이지는 메시지 전달을 사용하여 백그라운드 페이지와 통신할 수 있습니다. 예를 보려면 콘텐츠 스크립트 삽입을 참고하세요.

DevTools 확장 프로그램 만들기

확장 프로그램의 DevTools 페이지를 만들려면 확장 프로그램 매니페스트에 devtools_page 필드를 추가합니다.

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

확장 프로그램의 매니페스트에 지정된 devtools_page의 인스턴스는 열린 DevTools 창마다 생성됩니다. 이 페이지는 devtools.panels API를 사용하여 DevTools 창에 다른 확장 페이지를 패널 및 사이드바로 추가할 수 있습니다.

chrome.devtools.* API 모듈은 DevTools 창 내에 로드된 페이지에서만 사용할 수 있습니다. 콘텐츠 스크립트와 기타 확장 프로그램 페이지에는 이러한 API가 없습니다. 따라서 API는 DevTools 기간의 전체 기간 동안만 사용할 수 있습니다.

일부 DevTools API는 아직 실험 중입니다. chrome.experimental*을 참고하세요. API를 참조하세요.

DevTools UI 요소: 패널 및 사이드바 창

브라우저 작업, 컨텍스트 메뉴, 팝업과 같은 일반적인 확장 프로그램 UI 요소 외에도 DevTools 확장 프로그램은 UI 요소를 DevTools 창에 추가할 수 있습니다.

  • 패널은 요소, 소스, 네트워크 패널과 같은 최상위 탭입니다.
  • 사이드바 창은 패널과 관련된 추가 UI를 표시합니다. Elements 패널의 Styles, Computed Styles, Event Listeners 창이 사이드바 창의 예입니다. 사이드바 창의 모양은 사용 중인 Chrome 버전 및 DevTools 창이 도킹된 위치에 따라 이미지와 일치하지 않을 수 있습니다.

Elements 패널과 Styles 사이드바 창이 표시된 DevTools 창

각 패널은 자체 HTML 파일로, 자바스크립트, CSS, 이미지 등 다른 리소스를 포함할 수 있습니다. 기본 패널을 만드는 방법은 다음과 같습니다.

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

패널 또는 사이드바 창에서 실행된 자바스크립트는 DevTools 페이지와 동일한 API에 액세스할 수 있습니다.

요소 패널의 기본 사이드바 창을 만드는 코드는 다음과 같습니다.

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

사이드바 창에 콘텐츠를 표시하는 방법에는 여러 가지가 있습니다.

  • HTML 콘텐츠입니다. setPage를 호출하여 창에 표시할 HTML 페이지를 지정합니다.
  • JSON 데이터입니다. JSON 객체를 setObject에 전달합니다.
  • JavaScript 표현식입니다. 표현식을 setExpression에 전달합니다. DevTools는 검사된 페이지의 컨텍스트에서 표현식을 평가하고 반환 값을 표시합니다.

setObjectsetExpression 모두 창에는 DevTools 콘솔에 표시되는 것과 같은 값이 표시됩니다. 그러나 setExpression를 사용하면 DOM 요소와 임의의 JavaScript 객체를 표시할 수 있고 setObject는 JSON 객체만 지원합니다.

확장 구성요소 간 통신

다음 섹션에서는 DevTools 확장 프로그램의 여러 구성요소 간에 통신하기 위한 몇 가지 일반적인 시나리오를 설명합니다.

콘텐츠 스크립트 삽입

DevTools 페이지에서는 tabs.executeScript를 직접 호출할 수 없습니다. DevTools 페이지에서 콘텐츠 스크립트를 삽입하려면 inspectedWindow.tabId 속성을 사용하여 검사된 창의 탭 ID를 검색하고 백그라운드 페이지로 메시지를 보내야 합니다. 백그라운드 페이지에서 tabs.executeScript를 호출하여 스크립트를 삽입합니다.

다음 코드 스니펫은 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"
});

백그라운드 페이지 코드:

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

검사한 창에서 자바스크립트 평가

inspectedWindow.eval 메서드를 사용하여 검사된 페이지의 컨텍스트에서 자바스크립트 코드를 실행할 수 있습니다. DevTools 페이지, 패널 또는 사이드바 창에서 eval 메서드를 호출할 수 있습니다.

기본적으로 표현식은 페이지의 기본 프레임 컨텍스트에서 평가됩니다. 이제 요소 검사(inspect(elem)), 함수 중단 (debug(fn)), 클립보드에 복사 (copy())와 같은 DevTools 명령줄 API 기능에 익숙해졌을 것입니다. inspectedWindow.eval()는 DevTools 콘솔에 입력된 코드와 동일한 스크립트 실행 컨텍스트 및 옵션을 사용하므로 eval 내에서 이러한 API에 액세스할 수 있습니다. 예를 들어, SOAK는 이를 사용하여 요소를 검사합니다.

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

또는 inspectedWindow.eval()useContentScriptContext: true 옵션을 사용하여 콘텐츠 스크립트와 동일한 컨텍스트에서 표현식을 평가합니다. useContentScriptContext: trueeval를 호출하면 콘텐츠 스크립트 컨텍스트가 생성되지 않으므로 eval를 호출하기 전에 executeScript를 호출하거나 manifest.json 파일에 콘텐츠 스크립트를 지정하여 컨텍스트 스크립트를 로드해야 합니다.

컨텍스트 스크립트 컨텍스트가 존재하면 이 옵션을 사용하여 추가 콘텐츠 스크립트를 삽입할 수 있습니다.

eval 메서드는 올바른 상황에서 사용하면 효과적이며 부적절하게 사용하면 위험합니다. 검사된 페이지의 JavaScript 컨텍스트에 액세스할 필요가 없는 경우 tabs.executeScript 메서드를 사용합니다. 두 메서드의 자세한 주의사항과 비교는 inspectedWindow를 참고하세요.

선택한 요소를 콘텐츠 스크립트에 전달

콘텐츠 스크립트가 현재 선택된 요소에 직접 액세스할 수 없습니다. 하지만 inspectedWindow.eval를 사용하여 실행하는 모든 코드는 DevTools 콘솔 및 명령줄 API에 액세스할 수 있습니다. 예를 들어 평가된 코드에서 $0를 사용하면 선택된 요소에 액세스할 수 있습니다.

선택한 요소를 콘텐츠 스크립트에 전달하는 방법:

  • 콘텐츠 스크립트에서 선택된 요소를 인수로 사용하는 메서드를 만듭니다.
  • useContentScriptContext: true 옵션과 함께 inspectedWindow.eval를 사용하여 DevTools 페이지에서 메서드를 호출합니다.

콘텐츠 스크립트의 코드는 다음과 같을 수 있습니다.

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

다음과 같이 DevTools 페이지에서 메서드를 호출합니다.

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

useContentScriptContext: true 옵션은 콘텐츠 스크립트와 동일한 컨텍스트에서 표현식을 평가해야 setSelectedElement 메서드에 액세스할 수 있도록 지정합니다.

참조 패널의 window 가져오기

devtools 패널에서 postMessage하려면 window 객체에 대한 참조가 필요합니다. panel.onShown 이벤트 핸들러에서 패널의 iframe 창을 가져옵니다.

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

콘텐츠 스크립트에서 DevTools 페이지로 메시지 전송

DevTools 페이지와 콘텐츠 스크립트 간의 메시징은 백그라운드 페이지를 통해 간접적으로 이루어집니다.

콘텐츠 스크립트 메시지를 전송할 때 콘텐츠 스크립트 삽입에 나와 있는 것처럼 백그라운드 페이지에서 특정 탭의 콘텐츠 스크립트로 메시지를 전달하는 tabs.sendMessage 메서드를 사용할 수 있습니다.

콘텐츠 스크립트에서 메시지를 보낼 때 현재 탭과 연결된 올바른 DevTools 페이지 인스턴스로 메시지를 전달하기 위한 미리 준비된 방법은 없습니다. 이 문제를 해결하려면 DevTools 페이지가 백그라운드 페이지와 장기 연결을 설정하고 백그라운드 페이지에서 탭 ID와 연결 맵을 유지하게 하면 각 메시지를 올바른 연결로 라우팅할 수 있습니다.

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

DevTools 페이지 (또는 패널이나 사이드바 창)는 다음과 같이 연결을 설정합니다.

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

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

삽입된 스크립트에서 DevTools 페이지로 메시지 보내기

위의 솔루션은 콘텐츠 스크립트에서도 작동하지만 페이지에 직접 삽입된 코드(예: <script> 태그 추가 또는 inspectedWindow.eval를 통해)에는 다른 전략이 필요합니다. 이 컨텍스트에서 runtime.sendMessage는 예상대로 백그라운드 스크립트에 메시지를 전달하지 않습니다.

이 문제를 해결하려면 삽입된 스크립트를 중개자 역할을 하는 콘텐츠 스크립트와 결합할 수 있습니다. 콘텐츠 스크립트에 메시지를 전달하려면 window.postMessage API를 사용하면 됩니다. 다음 예는 이전 섹션의 백그라운드 스크립트를 사용한다고 가정합니다.

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

이제 메시지가 삽입된 스크립트에서 콘텐츠 스크립트, 백그라운드 스크립트, 마지막으로 DevTools 페이지로 이동합니다.

또한 두 가지 대체 메시지 전달 기법을 고려해 볼 수도 있습니다.

DevTools가 열리고 닫힐 때 감지

확장 프로그램에서 DevTools 창이 열려 있는지 추적해야 하는 경우 onConnect 리스너를 백그라운드 페이지에 추가하고 DevTools 페이지에서 connect를 호출하면 됩니다. 각 탭에서 자체 DevTools 창을 열 수 있으므로 여러 연결 이벤트를 수신할 수 있습니다. DevTools 창이 열려 있는지 추적하려면 아래와 같이 연결 및 연결 해제 이벤트를 집계해야 합니다.

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

DevTools 페이지는 다음과 같이 연결을 생성합니다.

// devtools.js

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

DevTools 확장 프로그램 예시

다음 DevTools 확장 프로그램 예시의 소스를 둘러보세요.

추가 정보

확장 프로그램에서 사용할 수 있는 표준 API에 관한 정보는 chrome.* API웹 API를 사용합니다.

의견 보내기 귀하의 의견과 제안은 API를 개선하는 데 도움이 됩니다.

샘플에서 DevTools API를 사용하는 예시를 확인할 수 있습니다.