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

Tổng quan

Tiện ích Công cụ cho nhà phát triển sẽ thêm chức năng vào Công cụ của Chrome cho nhà phát triển. Ứng dụng này có thể thêm bảng điều khiển giao diện người dùng mới và thanh bên, tương tác với trang đã kiểm tra, nhận thông tin về các yêu cầu mạng, v.v. Khung hiển thị các tiện ích Công cụ cho nhà phát triển nổi bật. Tiện ích Công cụ cho nhà phát triển có quyền truy cập vào tập hợp bổ sung API tiện ích dành riêng cho Công cụ cho nhà phát triển:

Tiện ích Công cụ cho nhà phát triển có cấu trúc giống như mọi tiện ích khác: tiện ích có thể có trang nền, nội dung tập lệnh và các mục khác. Ngoài ra, mỗi tiện ích của Công cụ cho nhà phát triển đều có một trang Công cụ cho nhà phát triển có quyền truy cập đối với API Công cụ cho nhà phát triển.

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

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

Một thực thể của trang Công cụ cho nhà phát triển của tiện ích sẽ được tạo mỗi khi cửa sổ Công cụ cho nhà phát triển mở ra. Chiến lược phát hành đĩa đơn Trang Công cụ cho nhà phát triển tồn tại trong suốt thời gian hoạt động của cửa sổ Công cụ cho nhà phát triển. 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 và một bộ API tiện ích giới hạn. Cụ thể, trang Công cụ cho nhà phát triển có thể:

  • Tạo và tương tác với các bảng điều khiển bằng API devtools.panels.
  • Nhận thông tin về cửa sổ đã kiểm tra và đánh giá mã trong cửa sổ được kiểm tra bằng cách sử dụng Các API devtools.inspectedWindow.
  • Nhận thông tin về các yêu cầu mạng bằng API devtools.network.

Trang Công cụ cho nhà phát triển không thể sử dụng trực tiếp hầu hết các API tiện ích. Ứng dụng này có quyền truy cập vào cùng một tập hợp con các API extensionruntime mà một tập lệnh nội dung có quyền truy cập vào. Nhấn thích một nội dung tập lệnh, trang Công cụ cho nhà phát triển có thể giao tiếp với trang nền bằng cách sử dụng tính năng Truyền thông báo. Đối với ví dụ: xem phần Chèn tập lệnh nội dung.

Tạo tiện ích Công cụ cho nhà phát triển

Để tạo 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 tiện ích tệp kê khai:

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

Một bản sao của devtools_page được chỉ định trong tệp kê khai của tiện ích sẽ được tạo cho mỗi Đã mở cửa sổ Công cụ cho nhà phát triển. Trang này có thể thêm các trang tiện ích khác dưới dạng bảng điều khiển và thanh bên vào Cửa sổ Công cụ cho nhà phát triển sử dụng API devtools.panels.

Các mô-đun API chrome.devtools.* chỉ có sẵn cho các trang được tải trong Công cụ cho nhà phát triển cửa sổ. Tập lệnh nội dung và các trang tiện ích khác không có những API này. Do đó, các API này chỉ có sẵn trong suốt vòng đời của cửa sổ Công cụ cho nhà phát triển.

Ngoài ra, còn có một số API Công cụ cho nhà phát triển vẫn đang trong quá trình thử nghiệm. Hãy tham khảo chrome.experimental.* API để biết danh sách API thử nghiệm và hướng dẫn về cách sử dụng chúng.

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 thành phần giao diện người dùng mở rộng thông thường, chẳng hạn như 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 Công cụ cho nhà phát triển 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à một 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 trình bày giao diện người dùng bổ sung liên quan đến một bảng điều khiển. Kiểu, Kiểu đã tính toán và Ngăn Trình xử lý sự kiện trên bảng điều khiển Phần tử là ví dụ về ngăn thanh bên. (Lưu ý rằng giao diện của ngăn thanh bên có thể không khớp với hình ảnh, tuỳ thuộc vào phiên bản Chrome mà bạn sử dụng và vị trí cửa sổ Công cụ cho nhà phát triển được gắn vào đế sạc.)

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.

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. bật). Cách tạo bảng điều khiển cơ bản có dạng như sau:

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

JavaScript được thực thi trong bảng điều khiển hoặc ngăn 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.

Việc tạo ngăn thanh bên cơ bản cho bảng điều khiển Phần tử có dạng như 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 vào setExpression. Công cụ cho nhà phát triển đánh giá trong ngữ cảnh của trang được kiểm tra đồng thời hiển thị giá trị trả về.

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

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

Các phần sau đây mô tả một số trường hợp điển hình liên lạc giữa những của tiện ích Công cụ cho nhà phát triển.

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

Trang Công cụ cho nhà phát triển không thể gọi trực tiếp tabs.executeScript. Để chèn một tập lệnh nội dung từ trang Công cụ cho nhà phát triển, bạn phải truy xuất mã nhận dạng của thẻ của cửa sổ được kiểm tra bằng cách sử dụng inspectedWindow.tabId rồi gửi thông báo đến trang nền. Từ trang nền, hãy gọi tabs.executeScript để chèn tập lệnh.

Các đoạn mã sau đây cho biết cách chèn tập lệnh nội dung bằng 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"
});

Mã cho trang nền:

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

Đá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 theo ngữ cảnh của đã kiểm tra. Bạn có thể gọi phương thức eval từ trang, bảng điều khiển hoặc ngăn thanh bên của Công cụ cho nhà phát triển.

Theo mặc định, biểu thức được đánh giá trong ngữ cảnh của khung chính của trang. Giờ đây, bạn có thể làm quen với các tính năng của API dòng lệnh trong Công cụ cho nhà phát triển, chẳng hạn như kiểm tra phần tử (inspect(elem)), ngắt hàm (debug(fn)), sao chép vào bảng nhớ tạm (copy()) và nhiều lệnh khác. inspectedWindow.eval() sử dụng cùng ngữ cảnh và tuỳ chọn thực thi tập lệnh với mã được nhập vào Bảng điều khiển Công cụ cho nhà phát triển, cho phép truy cập vào các API này trong eval. Ví dụ: SOAK sử dụng để kiểm tra một phần tử:

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

Ngoài ra, hãy sử dụng lựa chọn useContentScriptContext: true cho inspectedWindow.eval() để đánh giá biểu thức trong cùng ngữ cảnh với tập lệnh nội dung. Đang gọi eval bằng useContentScriptContext: true không tạo ngữ cảnh tập lệnh nội dung, vì vậy, bạn phải tải một tập lệnh ngữ cảnh trước khi gọi eval, bằng cách gọi executeScript hoặc bằng cách chỉ định nội dung trong tệp manifest.json.

Khi ngữ cảnh tập lệnh ngữ cảnh tồn tại, bạn có thể sử dụng tuỳ chọn này để chèn nội dung bổ sung các tập lệnh.

Phương thức eval mạnh mẽ khi được sử dụng trong bối cảnh phù hợp và nguy hiểm khi được sử dụng không phù hợp. Sử dụng phương thức tabs.executeScript nếu bạn không cần quyền truy cập vào Ngữ cảnh JavaScript của trang được kiểm tra. Để biết các cảnh báo chi tiết và so sánh hai phương pháp, xem inspectedWindow.

Chuyể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ử hiện đã chọn. Tuy nhiên, bất kỳ mã nào bạn thực thi bằng inspectedWindow.eval có quyền truy cập vào bảng điều khiển Công cụ cho nhà phát triển và API dòng lệnh. Ví dụ: trong mã được đá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 vào tập lệnh nội dung:

  • 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ố.
  • Gọi phương thức 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.

Mã trong tập lệnh nội dung của bạn có thể trông giống như sau:

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

Gọi phương thức từ trang Công cụ cho nhà phát triển như sau:

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 như tập lệnh nội dung, để có thể truy cập vào phương thức setSelectedElement.

Lấy window của bảng tham chiếu

Để postMessage từ bảng điều khiển devtools, bạn cần tham chiếu đến đối tượng window của bảng đó. Lấy cửa sổ iframe của bảng điều khiển thông qua trình xử lý sự kiện panel.onShown:

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

Thông báo từ tập lệnh nội dung đến trang Công cụ cho nhà phát triển

Thông báo giữa trang Công cụ cho nhà phát triển và các tập lệnh nội dung là gián tiếp, thông qua trang nền.

Khi gửi thông báo đến một tập lệnh nội dung, trang nền có thể sử dụng Phương thức tabs.sendMessage chuyển hướng một thông báo đến tập lệnh nội dung trong một thẻ cụ thể, như minh hoạ trong đoạn mã Chèn tập lệnh nội dung.

Khi gửi thư từ một tập lệnh nội dung, bạn không thể sử dụng phương thức tạo sẵn nào để gửi thư vào đúng phiên bản của trang Công cụ cho nhà phát triển được liên kết với thẻ hiện tại. Để giải quyết sự cố này, bạn có thể trang Công cụ cho nhà phát triển thiết lập một kết nối lâu dài với trang nền và có trang nền lưu một bản đồ ID thẻ cho các kết nối, để nó có thể định tuyến từng thông báo đến đúng kết nối.

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

Trang Công cụ cho nhà phát triển (hoặc bảng điều khiển hoặc ngăn thanh bên) thiết lập kết nối như sau:

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

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

Thông báo từ các tập lệnh được chèn tới trang Công cụ cho nhà phát triển

Mặc dù giải pháp ở trên phù hợp với tập lệnh nội dung, nhưng mã được chèn trực tiếp vào trang (ví dụ: thông qua việc thêm thẻ <script> hoặc thông qua inspectedWindow.eval) phải có chiến lược khác nhau. Trong trường hợp này, runtime.sendMessage sẽ không chuyển thông báo đến tập lệnh nền như dự kiến.

Để giải quyết sự cố này, bạn có thể kết hợp tập lệnh được chèn với tập lệnh nội dung hoạt động như một trung gian. Để chuyển thông báo đến tập lệnh nội dung, bạn có thể sử dụng window.postMessage API. Dưới đây là ví dụ, giả sử 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
  if (typeof message !== 'object' || message === null ||
      !message.source === 'my-devtools-extension') {
    return;
  }

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

Bây giờ, thông báo của bạn sẽ chuyển từ tập lệnh được chèn đến tập lệnh nội dung, đến nền và cuối cùng là đến trang Công cụ cho nhà phát triển.

Bạn cũng có thể cân nhắc hai kỹ thuật truyền thông báo thay thế tại đây.

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

Nếu tiện ích của bạn cần theo dõi xem cửa sổ Công cụ cho nhà phát triển có đang mở hay không, bạn có thể thêm onConnect trình nghe sang trang nền và gọi connect từ trang Công cụ cho nhà phát triển. Vì mỗi thẻ có thể có cửa sổ Công cụ cho nhà phát triển riêng đang mở, 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 đang mở, bạn cần tính các sự kiện kết nối và ngắt kết nối như minh hoạ dưới đây:

// 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 kết nối như sau:

// devtools.js

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

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

Duyệt xem nguồn của các ví dụ về tiện ích Công cụ cho nhà phát triển sau đây:

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.* APIweb API.

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

Ví dụ

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