Tổng quan
Tiện ích DevTools bổ sung chức năng cho Chrome DevTools. Tiện ích này có thể thêm các bảng điều khiển và thanh bên mới cho giao diện người dùng, tương tác với trang được kiểm tra, lấy thông tin về các yêu cầu mạng, v.v. Xem các tiện ích được đề xuất của Công cụ cho nhà phát triển. Các tiện ích của Công cụ cho nhà phát triển có quyền truy cập vào một nhóm API tiện ích dành riêng cho Công cụ cho nhà phát triển:
Tiện ích DevTools có cấu trúc giống như mọi tiện ích khác: tiện ích này có thể có trang nền, tập lệnh nội dung và các mục khác. Ngoài ra, mỗi tiện ích 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 vào các API Công cụ cho nhà phát triển.

Trang Công cụ cho nhà phát triển
Một phiên bản của trang Công cụ cho nhà phát triển của tiện ích sẽ được tạo mỗi khi một cửa sổ Công cụ cho nhà phát triển mở ra. 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 số ít API tiện ích. Cụ thể, trang Công cụ cho nhà phát triển có thể:
- Tạo và tương tác với bảng điều khiển bằng API
devtools.panels. - Nhận 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ách sử dụng API
devtools.inspectedWindow. - Nhận thông tin về các yêu cầu mạng bằng cách sử dụ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. Nó có quyền truy cập vào cùng một tập hợp con của API extension và runtime mà một tập lệnh nội dung có quyền truy cập. Giống như một tập lệnh nội dung, 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 Truyền thông báo. Để xem ví dụ, hãy xem phần Chèn tập lệnh nội dung.
Tạo một tiện ích Công cụ cho nhà phát triển
Để tạo một trang Công cụ cho nhà phát triển cho tiện ích, hãy thêm trường devtools_page vào tệp kê khai tiện ích:
{
"name": ...
"version": "1.0",
"minimum_chrome_version": "10.0",
"devtools_page": "devtools.html",
...
}
Một phiên bản của devtools_page được chỉ định trong tệp kê khai của tiện ích sẽ được tạo cho mọi cửa sổ Công cụ cho nhà phát triển đã mở. 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 bằng cách sử dụng API devtools.panels.
Các mô-đun API chrome.devtools.* chỉ có sẵn cho những trang được tải trong cửa sổ Công cụ cho nhà phát triển. Tập lệnh nội dung và các trang tiện ích khác không có các API này. Do đó, các API này chỉ có trong suốt thời gian tồn tại của cửa sổ Công cụ cho nhà phát triển.
Ngoài ra, một số API của Công cụ cho nhà phát triển vẫn đang trong giai đoạn thử nghiệm. Tham khảo chrome.experimental.* API cho danh sách API thử nghiệm và hướng dẫn về cách sử dụng các API đó.
Các 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 bên
Ngoài các phần tử giao diện người dùng tiện ích 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 DevTools có thể thêm các phần tử giao diện người dùng vào cửa sổ DevTools:
- 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 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. Các ngăn Styles (Kiểu), Computed Styles (Kiểu đã tính toán) và Event Listeners (Trình nghe sự kiện) trên bảng Elements (Phần tử) là ví dụ về các ngăn bên. (Xin lưu ý rằng giao diện của các ngăn 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 đang sử dụng và vị trí gắn cửa sổ Công cụ cho nhà phát triển.)

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.). Cách tạo một bảng điều khiển cơ bản:
chrome.devtools.panels.create("My Panel",
"MyPanelIcon.png",
"Panel.html",
function(panel) {
// code invoked on panel creation
}
);
JavaScript được thực thi trong một bảng điều khiển hoặc ngăn bên có quyền truy cập vào cùng một API như trang Công cụ cho nhà phát triển.
Việc tạo một ngăn bên cơ bản cho bảng điều khiển Elements (Phần tử) sẽ 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 bên:
- Nội dung HTML. Gọi
setPageđể chỉ định một trang HTML sẽ 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 bối cảnh của trang được kiểm tra và hiển thị giá trị trả về.
Đối với cả setObject và setExpression, ngăn này sẽ hiển thị giá trị như giá trị 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à các đối tượng 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 của tiện ích
Các phần sau đây mô tả một số trường hợp điển hình để giao tiếp giữa các thành phần khác nhau của một tiện ích DevTools.
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 sổ được kiểm tra bằng cách sử dụng thuộc tính inspectedWindow.tabId và gửi một 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 thấy cách chèn một 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 trong bối cảnh của trang được kiểm tra. Bạn có thể gọi phương thức eval từ một trang, bảng điều khiển hoặc ngăn 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 bối cảnh của khung chính của trang. Giờ đây, bạn có thể đã quen thuộc với các tính năng API dòng lệnh của Công cụ cho nhà phát triển như kiểm tra phần tử (inspect(elem)), ngắt các hàm (debug(fn)), sao chép vào bảng nhớ tạm (copy()) và nhiều tính năng khác.
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 tại bảng điều khiển DevTools, cho phép truy cập vào các API này trong 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) { }
);
Ngoài ra, hãy 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. Việc gọi eval bằng useContentScriptContext: true sẽ 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 một tập lệnh nội dung trong tệp manifest.json.
Sau khi ngữ cảnh tập lệnh nội dung tồn tại, bạn có thể dùng lựa chọn này để chèn thêm tập lệnh nội dung.
Phương thức eval rất hiệu quả khi được dùng trong đúng ngữ cảnh và nguy hiểm khi được dùng không đúng cách. Sử dụng phương thức tabs.executeScript nếu bạn không cần truy cập vào ngữ cảnh JavaScript của trang được kiểm tra. Để biết thông tin chi tiết về các cảnh báo và so sánh hai phương thức này, hãy xem inspectedWindow.
Truyền phần tử đã chọn đến một 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 được chọn. 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 DevTools và các 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.
Cách truyền phần tử đã chọn đến một tập lệnh nội dung:
- Tạo một phương thức trong tập lệnh nội dung nhận 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.evalvới lựa chọnuseContentScriptContext: true.
Mã trong tập lệnh nội dung có thể có dạ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 });
Lựa chọn useContentScriptContext: true chỉ định rằng biểu thức phải được đánh giá trong cùng một ngữ cảnh với tập lệnh nội dung, vì vậy, biểu thức có thể truy cập vào phương thức setSelectedElement.
Lấy window của bảng điều khiển tham chiếu
Để postMessage từ một bảng điều khiển công cụ cho nhà phát triển, bạn cần có một thông tin tham chiếu đến đối tượng window của bảng điều khiển đó.
Lấy cửa sổ iframe của bảng điều khiển từ trình xử lý sự kiện panel.onShown:
onShown.addListener(function callback)
extensionPanel.onShown.addListener(function (extPanelWindow) {
extPanelWindow instanceof Window; // true
extPanelWindow.postMessage( // …
});
Nhắn tin từ tập lệnh nội dung đến trang Công cụ cho nhà phát triển
Việc truyền thông điệp giữa trang Công cụ cho nhà phát triển và 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. Phương thức này chuyển một thông báo đến các tập lệnh nội dung trong một thẻ cụ thể, như minh hoạ trong phần Chèn tập lệnh nội dung.
Khi gửi một thông báo từ một tập lệnh nội dung, không có phương thức có sẵn nào để gửi thông báo đến đúng phiên bản trang Công cụ cho nhà phát triển được liên kết với thẻ hiện tại. Để khắc phục, bạn có thể để trang Công cụ cho nhà phát triển thiết lập một mối kết nối lâu dài với trang nền và để trang nền lưu giữ một bản đồ mã nhận dạng thẻ với các mối kết nối, nhờ đó, trang nền có thể định tuyến từng thông báo đến đúng mối 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 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
});
Nhắn tin từ các tập lệnh được chèn vào trang Công cụ cho nhà phát triển
Mặc dù giải pháp trên hoạt động đối với các 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 nối thẻ <script> hoặc thông qua inspectedWindow.eval) yêu cầu một chiến lược khác. Trong ngữ cảnh này, runtime.sendMessage sẽ không truyền thông báo đến tập lệnh nền như mong đợi.
Để khắc phục, bạn có thể kết hợp tập lệnh được chèn với một tập lệnh nội dung đóng vai trò là trung gian. Để truyền thông báo đến tập lệnh nội dung, bạn có thể sử dụng API window.postMessage. Dưới đây là một ví dụ, giả sử tập lệnh nền ở 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);
});
Giờ đây, thông báo của bạn sẽ chuyển từ tập lệnh được chèn, sang tập lệnh nội dung, sang tập lệnh 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 Công cụ cho nhà phát triển mở và đóng
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 trình nghe onConnect vào trang nền 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, bạn cần đếm 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 sẽ tạo một 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 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 này:
- Tiện ích Polymer Devtools – sử dụng nhiều trình trợ giúp chạy trong trang lưu trữ để truy vấn trạng thái DOM/JS nhằm gửi lại cho bảng điều khiển tuỳ chỉnh.
- Tiện ích React DevTools – Sử dụng một mô-đun con của Blink để dùng lại các thành phần giao diện người dùng của Công cụ cho nhà phát triển.
- Ember Inspector – Tiện ích dùng chung có các bộ chuyển đổi cho cả Chrome và Firefox.
- Coquette-inspect – Một tiện ích dựa trên React gọn gàng với một tác nhân gỡ lỗi được chèn vào trang lưu trữ.
- Thư viện tiện ích DevTools và Tiện ích mẫu của chúng tôi có nhiều ứng dụng đáng cài đặt, dùng thử và học hỏi hơn.
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.* API và API web.
Gửi ý kiến phản hồi cho chúng tôi! Ý kiến 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 này.
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.