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에서 실험용 API 목록과 사용 방법에 관한 가이드라인을 확인하세요.

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

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

  • 패널은 요소, 소스, 네트워크 패널과 같은 최상위 탭입니다.
  • 측면 패널은 패널과 관련된 보조 UI를 표시합니다. 요소 패널의 스타일, 계산된 스타일, 이벤트 리스너 창은 사이드바 창의 예입니다. 사용 중인 Chrome 버전과 DevTools 창이 도킹된 위치에 따라 사이드바 창의 모양이 이미지와 일치하지 않을 수 있습니다.

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

각 패널은 자체 HTML 파일이며 여기에는 다른 리소스 (JavaScript, CSS, 이미지 등)가 포함될 수 있습니다. 기본 패널을 만드는 방법은 다음과 같습니다.

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

패널 또는 사이드바 창에서 실행되는 JavaScript는 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);
    });
});

검사된 창에서 JavaScript 평가

inspectedWindow.eval 메서드를 사용하여 검사된 페이지의 컨텍스트에서 JavaScript 코드를 실행할 수 있습니다. 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: true를 사용하여 eval를 호출해도 콘텐츠 스크립트 컨텍스트가 create되지 않으므로 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를 사용하는 예시는 샘플에서 확인할 수 있습니다.