Mở rộng Công cụ cho nhà phát triển

Tiện ích Công cụ cho nhà phát triển thêm các tính năng vào Công cụ của Chrome cho nhà phát triển bằng cách truy cập vào các API tiện ích dành riêng cho Công cụ cho nhà phát triển thông qua một trang Công cụ cho nhà phát triển được thêm vào tiện ích.

Sơ đồ cấu trúc cho thấy trang Công cụ cho nhà phát triển giao tiếp với cửa sổ đã kiểm tra và trình chạy dịch vụ. Bạn sẽ thấy trình chạy dịch vụ này giao tiếp với các tập lệnh nội dung và truy cập vào các API tiện ích.
         Trang Công cụ cho nhà phát triển có quyền truy cập vào API Công cụ cho nhà phát triển, chẳng hạn như tạo bảng điều khiển.
Cấu trúc tiện ích của DevTools.

Các API tiện ích dành riêng cho Công cụ cho nhà phát triển bao gồm:

Trang Công cụ cho nhà phát triển

Khi cửa sổ Công cụ cho nhà phát triển mở ra, tiện ích Công cụ cho nhà phát triển sẽ tạo một bản sao của trang Công cụ cho nhà phát triển tồn tại miễn là cửa sổ đang mở. Trang này có quyền truy cập vào API tiện ích và API Công cụ cho nhà phát triển, đồng thời có thể làm những việc sau:

  • Tạo và tương tác với bảng điều khiển bằng API devtools.panels, bao gồm cả việc thêm các trang tiện ích khác dưới dạng bảng điều khiển hoặc thanh bên vào cửa sổ Công cụ cho nhà phát triển.
  • Lấy thông tin về cửa sổ được kiểm tra và đánh giá mã trong cửa sổ được kiểm tra bằng các API devtools.inspectedWindow.
  • Nhận thông tin về các yêu cầu mạng bằng cách sử dụng các API devtools.network.
  • Mở rộng bảng điều khiển Máy ghi âm bằng các API devtools.recorder.

Trang Công cụ cho nhà phát triển có thể truy cập trực tiếp vào các API tiện ích. Điều này bao gồm việc có thể giao tiếp với trình chạy dịch vụ bằng cách sử dụng tính năng truyền thông báo.

Tạo tiện ích cho nhà phát triển

Để tạo một trang Công cụ cho nhà phát triển cho tiện ích của bạn, hãy thêm trường devtools_page vào tệp kê khai tiện ích:

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

Trường devtools_page phải trỏ đến một trang HTML. Vì trang Công cụ cho nhà phát triển phải nằm trên tiện ích của bạn, bạn nên chỉ định trang này bằng URL tương đối.

Các thành phần của API chrome.devtools chỉ có sẵn cho các trang được tải trong cửa sổ Công cụ cho nhà phát triển khi cửa sổ đó đang mở. Tập lệnh nội dung và các trang tiện ích khác không có quyền truy cập vào các API này.

Phần tử trên giao diện người dùng của Công cụ cho nhà phát triển: bảng điều khiển và ngăn thanh bên

Ngoài các phần tử tiện ích trên giao diện người dùng thông thường, chẳng hạn như các thao tác trên trình duyệt, trình đơn theo bối cảnh và cửa sổ bật lên, tiện ích DevTools có thể thêm các phần tử trên giao diện người dùng vào cửa sổ Công cụ cho nhà phát triển:

  • Bảng điều khiển là thẻ cấp cao nhất, chẳng hạn như bảng điều khiển Phần tử, Nguồn và Mạng.
  • Ngăn thanh bên hiển thị giao diện người dùng bổ sung liên quan đến bảng điều khiển. Các ngăn Kiểu, Kiểu tính toán và Trình xử lý sự kiện trên bảng điều khiển Phần tử là các ví dụ về ngăn thanh bên. Tùy thuộc vào phiên bản Chrome bạn đang sử dụng và vị trí gắn cửa sổ Công cụ cho nhà phát triển, các ngăn thanh bên có thể trông giống như hình ảnh ví dụ sau:
Cửa sổ Công cụ cho nhà phát triển hiển thị bảng điều khiển Phần tử và ngăn thanh bên Kiểu.
Cửa sổ DevTools hiển thị bảng điều khiển Phần tử và ngăn thanh bên Kiểu.

Mỗi bảng điều khiển là một tệp HTML riêng, có thể bao gồm các tài nguyên khác (JavaScript, CSS, hình ảnh, v.v.). Để tạo một bảng điều khiển cơ bản, hãy sử dụng mã sau:

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

JavaScript được thực thi trong ngăn bảng điều khiển hoặc thanh bên có quyền truy cập vào cùng các API như trang Công cụ cho nhà phát triển.

Để tạo một ngăn thanh bên cơ bản, hãy sử dụng mã sau:

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

Có một số cách để hiển thị nội dung trong ngăn thanh bên:

  • Nội dung HTML: Gọi setPage() để chỉ định một trang HTML cần hiển thị trong ngăn.
  • Dữ liệu JSON: Truyền một đối tượng JSON đến setObject().
  • Biểu thức JavaScript: Truyền một biểu thức đến setExpression(). Công cụ cho nhà phát triển đánh giá biểu thức trong ngữ cảnh của trang được kiểm tra, sau đó hiển thị giá trị trả về.

Đối với cả setObject()setExpression(), ngăn này sẽ hiển thị giá trị như sẽ xuất hiện trong bảng điều khiển DevTools. Tuy nhiên, setExpression() cho phép bạn hiển thị các phần tử DOM và đối tượng JavaScript tuỳ ý, trong khi setObject() chỉ hỗ trợ đối tượng JSON.

Giao tiếp giữa các thành phần của tiện ích

Các phần sau đây mô tả một số cách hữu ích để cho phép các thành phần tiện ích Công cụ cho nhà phát triển giao tiếp với nhau.

Chèn tập lệnh nội dung

Để chèn một tập lệnh nội dung, hãy sử dụng scripting.executeScript():

// DevTools page -- devtools.js
chrome.scripting.executeScript({
  target: {
    tabId: chrome.devtools.inspectedWindow.tabId
  },
  files: ["content_script.js"]
});

Bạn có thể truy xuất mã thẻ của cửa sổ được kiểm tra bằng cách sử dụng thuộc tính inspectedWindow.tabId.

Nếu một tập lệnh nội dung đã được chèn, bạn có thể sử dụng các API thông báo để giao tiếp với tập lệnh đó.

Đánh giá JavaScript trong cửa sổ được kiểm tra

Bạn có thể sử dụng phương thức inspectedWindow.eval() để thực thi mã JavaScript trong bối cảnh trang được kiểm tra. Bạn có thể gọi phương thức eval() từ trang Công cụ cho nhà phát triển, bảng điều khiển hoặc ngăn thanh bên.

Theo mặc định, biểu thức được đánh giá trong ngữ cảnh của khung chính của trang. inspectedWindow.eval() sử dụng cùng một ngữ cảnh và các lựa chọn thực thi tập lệnh như mã được nhập trong bảng điều khiển Công cụ cho nhà phát triển. Nhờ đó, bạn có thể truy cập vào các tính năng của API Tiện ích Bảng điều khiển cho Công cụ cho nhà phát triển khi sử dụng eval(). Ví dụ: SOAK sử dụng nó để kiểm tra một phần tử:

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

Bạn cũng có thể đặt useContentScriptContext thành true khi gọi inspectedWindow.eval() để đánh giá biểu thức trong cùng ngữ cảnh với tập lệnh nội dung. Để dùng tuỳ chọn này, hãy sử dụng phần khai báo tập lệnh nội dung tĩnh trước khi gọi eval(), bằng cách gọi executeScript() hoặc chỉ định một tập lệnh nội dung trong tệp manifest.json. Sau khi ngữ cảnh tập lệnh ngữ cảnh tải, bạn cũng có thể sử dụng tuỳ chọn này để chèn tập lệnh nội dung bổ sung.

Truyền phần tử đã chọn vào tập lệnh nội dung

Tập lệnh nội dung không có quyền truy cập trực tiếp vào phần tử đã chọn hiện tại. Tuy nhiên, mọi mã bạn thực thi bằng inspectedWindow.eval() đều có quyền truy cập vào Bảng điều khiển công cụ cho nhà phát triển và các API Tiện ích bảng điều khiển. Ví dụ: trong mã đã đánh giá, bạn có thể sử dụng $0 để truy cập vào phần tử đã chọn.

Để chuyển phần tử đã chọn đến tập lệnh nội dung:

  1. Tạo một phương thức trong tập lệnh nội dung để lấy phần tử đã chọn làm đối số.

    function setSelectedElement(el) {
        // do something with the selected element
    }
    
  2. Gọi phương thức này từ trang Công cụ cho nhà phát triển bằng cách sử dụng inspectedWindow.eval() với tuỳ chọn useContentScriptContext: true.

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

Tuỳ chọn useContentScriptContext: true chỉ định rằng biểu thức phải được đánh giá trong cùng ngữ cảnh với tập lệnh nội dung để có thể truy cập vào phương thức setSelectedElement.

Nhận window của bảng tham chiếu

Để gọi postMessage() từ bảng điều khiển công cụ cho nhà phát triển, bạn cần tham chiếu đến đối tượng window của bảng điều khiển đó. Tải cửa sổ iframe của bảng điều khiển từ trình xử lý sự kiện panel.onShown:

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

Gửi thông báo từ các tập lệnh đã chèn đến trang Công cụ cho nhà phát triển

Mã được chèn trực tiếp vào trang mà không có tập lệnh nội dung, kể cả bằng cách thêm thẻ <script> hoặc gọi inspectedWindow.eval(), sẽ không thể gửi thông báo đến trang DevTools bằng runtime.sendMessage(). Thay vào đó, bạn nên kết hợp tập lệnh đã chèn với một tập lệnh nội dung có thể đóng vai trò là bên trung gian, đồng thời sử dụng phương thức window.postMessage(). Ví dụ sau sử dụng tập lệnh nền từ phần trước:

// 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. Note that this is not foolproof
  // and the page can easily spoof messages if it wants to.
  if (typeof message !== 'object' || message === null ||
      message.source !== 'my-devtools-extension') {
    return;
  }

  chrome.runtime.sendMessage(message);
});

Bạn có thể xem các kỹ thuật chuyển thư khác trên GitHub.

Phát hiện thời điểm Công cụ cho nhà phát triển mở và đóng

Để theo dõi xem cửa sổ Công cụ cho nhà phát triển có đang mở hay không, hãy thêm trình nghe onConnect vào trình chạy dịch vụ và gọi connect() từ trang Công cụ cho nhà phát triển. Vì mỗi thẻ có thể mở cửa sổ Công cụ cho nhà phát triển riêng, nên bạn có thể nhận được nhiều sự kiện kết nối. Để theo dõi xem có cửa sổ Công cụ cho nhà phát triển nào đang mở hay không, hãy đếm các sự kiện kết nối và ngắt kết nối như trong ví dụ sau:

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

Trang Công cụ cho nhà phát triển tạo một kết nối như sau:

// devtools.js

// Create a connection to the service worker
const serviceWorkerConnection = chrome.runtime.connect({
    name: "devtools-page"
});

// Send a periodic heartbeat to keep the port open.
setInterval(() => {
  port.postMessage("heartbeat");
}, 15000);

Ví dụ về tiện ích Công cụ cho nhà phát triển

Ví dụ trên trang này là từ các trang sau:

  • Tiện ích Polymer Devtools – Sử dụng nhiều trình trợ giúp chạy trên trang lưu trữ để truy vấn trạng thái DOM/JS nhằm gửi lại bảng điều khiển tuỳ chỉnh.
  • Phản hồi Tiện ích Công cụ cho nhà phát triển – Sử dụng mô-đun con của trình kết xuất để sử dụng lại các thành phần trên giao diện người dùng cho Công cụ cho nhà phát triển.
  • Ember Inspector – Lõi tiện ích dùng chung với bộ điều hợp cho cả Chrome và Firefox.
  • Coquette-inspect – Một tiện ích dựa trên React sạch với một tác nhân gỡ lỗi được chèn vào trang lưu trữ.
  • Tiện ích mẫu có nhiều tiện ích đáng giá hơn để bạn cài đặt, dùng thử và học hỏi.

Thông tin khác

Để biết thông tin về các API tiêu chuẩn mà tiện ích có thể sử dụng, hãy xem chrome.* APIAPI web.

Gửi ý kiến phản hồi cho chúng tôi! Các nhận xét và đề xuất của bạn sẽ giúp chúng tôi cải thiện các API.

Ví dụ

Bạn có thể tìm thấy các ví dụ sử dụng API Công cụ cho nhà phát triển trong phần Mẫu.