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 페이지는 대부분의 확장 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 창에 devtools.panels API를 사용하여 추가할 수 있습니다.

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

아직 실험 중인 일부 DevTools API도 있습니다. 실험용 API 목록 및 사용 방법에 관한 가이드는 chrome.experimental.* API를 참고하세요.

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

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

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

요소 패널과 스타일 사이드바 창이 표시된 DevTools 창

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

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를 검색하고 백그라운드 페이지에 메시지를 보내야 합니다.inspectedWindow.tabId 백그라운드 페이지에서 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 메서드를 호출할 수 있습니다.

기본적으로 표현식은 페이지의 기본 프레임 컨텍스트에서 평가됩니다. 이제 DevTools 명령줄 API 기능(예: 요소 검사 (inspect(elem)), 함수 중단(debug(fn)), 클립보드에 복사(copy()))에 익숙해졌을 것입니다. 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을 호출해도 콘텐츠 스크립트 컨텍스트가 생성 되지 않으므로 executeScript를 호출하거나 manifest.json 파일에 콘텐츠 스크립트를 지정하여 eval을 호출하기 전에 컨텍스트 스크립트를 로드해야 합니다.

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

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를 사용하는 예를 확인할 수 있습니다.