扩展开发者工具

注意:此页面描述了 Firefox 55 中的开发者工具 API。虽然这些 API 基于Chrome 开发者工具 API,但 Firefox 并未实现所有这些功能;因此,此处未记录所有功能。要查看哪些功能缺失,请参阅开发者工具 API 的限制

您可以使用 WebExtensions API 扩展浏览器的内置开发者工具。要创建开发者工具扩展,请在你的manifest.json 文件中包含“devtools_page”键。

json
"devtools_page": "devtools/devtools-page.html"

此键的值是一个指向与你的扩展捆绑在一起的 HTML 文件的 URL,这是一个称为开发者工具页面的特殊扩展页面。该 URL 必须相对于 manifest.json 文件。

此清单键隐式设置了“devtools”权限,这会触发关于开发者工具的安装时权限警告。为避免此警告,请通过在optional_permissions清单键中列出“devtools”权限来将该功能标记为可选。在更新中引入开发者工具功能时,设置可选权限尤其有用,因为它可以防止扩展被禁用(在 Chrome 中)或阻止更新(在 Firefox 中)。

开发者工具页面

当浏览器开发者工具打开时加载开发者工具页面,并在关闭时卸载。请注意,由于开发者工具窗口与单个选项卡关联,因此很有可能同时存在多个开发者工具窗口 - 因此可能存在多个开发者工具页面。

开发者工具页面没有任何可见的 DOM,但可以使用<script>标签包含 JavaScript 源代码。源代码必须与扩展本身捆绑在一起。源代码可以访问

请注意,开发者工具页面无法访问任何其他 WebExtension API,并且后台页面也无法访问开发者工具 API。相反,开发者工具页面和后台页面必须使用runtime消息传递 API 进行通信。以下是一个示例

html
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <title>DevTools Extension</title>
  </head>
  <body>
    <script src="devtools.js"></script>
  </body>
</html>

devtools.js文件将保存创建开发者工具扩展的实际代码。

创建面板

开发者工具窗口托管了许多单独的工具 - JavaScript 调试器、网络监视器等。顶部的一排选项卡允许用户在不同的工具之间切换。托管每个工具用户界面的窗口称为“面板”。

使用devtools.panels.create() API,你可以在开发者工具窗口中创建自己的面板。

js
browser.devtools.panels
  .create(
    "My Panel", // title
    "/icons/star.png", // icon
    "/devtools/panel/panel.html", // content
  )
  .then((newPanel) => {
    newPanel.onShown.addListener(initialisePanel);
    newPanel.onHidden.addListener(unInitialisePanel);
  });

这需要三个必填参数:面板的标题、图标和内容。它返回一个Promise,该 Promise 解析为一个devtools.panels.ExtensionPanel对象,表示新面板。

与目标窗口交互

开发者工具始终附加到特定的浏览器选项卡。这被称为开发者工具的“目标”或“被检查的窗口”。你可以使用devtools.inspectedWindow API 与被检查的窗口交互。

在目标窗口中运行代码

devtools.inspectedWindow.eval()提供了一种在被检查的窗口中运行代码的方法。

这有点像使用tabs.executeScript()注入内容脚本,但有一个重要的区别

  • 与内容脚本不同,使用devtools.inspectedWindow.eval()加载的脚本**不会**获得“DOM 的干净视图”:也就是说,它们可以看到页面脚本对页面的更改。

注意:DOM 的干净视图是一项安全功能,旨在帮助防止恶意页面通过重新定义原生 DOM 函数的行为来欺骗扩展。这意味着你使用 eval() 时需要非常小心,如果可以,应该使用普通的内容脚本。

使用devtools.inspectedWindow.eval()加载的脚本也看不到内容脚本定义的任何 JavaScript 变量。

使用内容脚本

开发者工具文档无法直接访问tabs.executeScript(),因此,如果你需要注入内容脚本,开发者工具文档必须向后台脚本发送消息,要求它注入脚本。devtools.inspectedWindow.tabId提供目标选项卡的 ID:开发者工具文档可以将其传递给后台脚本,后台脚本又可以将其传递给tabs.executeScript()

js
// devtools-panel.js

const scriptToAttach = "document.body.innerHTML = 'Hi from the devtools';";

window.addEventListener("click", () => {
  browser.runtime.sendMessage({
    tabId: browser.devtools.inspectedWindow.tabId,
    script: scriptToAttach,
  });
});
js
// background.js

function handleMessage(request, sender, sendResponse) {
  browser.tabs.executeScript(request.tabId, {
    code: request.script,
  });
}

browser.runtime.onMessage.addListener(handleMessage);

如果你需要在目标窗口中运行的内容脚本和开发者工具文档之间交换消息,最好使用runtime.connect()runtime.onConnect在后台页面和开发者工具文档之间建立连接。然后,后台页面可以维护选项卡 ID 和runtime.Port对象之间的映射,并使用此映射在两个作用域之间路由消息。

The background page tab ID is connected to the content script on the content page by a runtime.sendmessage() object. The Port of the background page is connected to the port of the Devtools document by a port.postMessage() object.

开发者工具 API 的限制

这些 API 基于 Chrome 开发者工具 API,但与 Chrome 相比,许多功能仍缺失。本节列出了截至 Firefox 54 尚未实现的功能。请注意,开发者工具 API 正在积极开发中,我们预计将在未来的版本中添加对其中大部分功能的支持。

devtools.inspectedWindow

以下功能不受支持

  • inspectedWindow.getResources()
  • inspectedWindow.onResourceAdded
  • inspectedWindow.onResourceContentCommitted

inspectedWindow.eval() 的所有选项都不受支持。

使用inspectedWindow.eval()注入的脚本无法使用控制台的所有命令行帮助器函数,但$0inspect()都受支持(从 Firefox 55 开始)。

devtools.panels

以下功能不受支持

  • panels.elements
  • panels.sources
  • panels.setOpenResourceHandler()
  • panels.openResource()
  • panels.ExtensionPanel.createStatusBarButton()
  • panels.Button
  • panels.ElementsPanel
  • panels.SourcesPanel

示例

GitHub 上的 webextensions-examples 仓库包含了几个使用开发者工具面板的扩展示例