Skip to content

Latest commit

 

History

History
485 lines (369 loc) · 20.7 KB

File metadata and controls

485 lines (369 loc) · 20.7 KB
title Code for Custom DevTools tool
description Files and code in the Custom DevTools tool sample, which is a Microsoft Edge extension you can modify. How the sample creates its own panel and interacts with the DevTools extension APIs.
author MSEdgeTeam
ms.author msedgedevrel
ms.topic article
ms.service microsoft-edge
ms.subservice extensions
ms.date 04/06/2026

Code for Custom DevTools tool

The Custom DevTools Tool sample consists of the following files and code. The code that interacts with the inspected webpage does the following:

  • Displays memory information in the Custom DevTools tool.

  • Displays the mouse-click position in the Custom DevTools tool, when the webpage is clicked.

  • Displays a greeting alert in the inspected webpage, when the Say Hello button is clicked in the Custom DevTools tool.

See also:

Architecture

The DevTools page, inspected page, content script, and background service worker fit together in an extension:

Diagram showing the anatomy of a DevTools extension

The content_script.js detects where the user clicks on the inspected webpage:

document.addEventListener("click", (event) => {
  chrome.runtime.sendMessage({
      click: true,
      xPosition: event.clientX + document.body.scrollLeft,
      yPosition: event.clientY + document.body.scrollTop

The content script relays this info to the devtools.js file, where the data is displayed in DevTools in the Custom tool and in the Console tool.

Overview of files

File Description
manifest.json Information about the extension: name, description, version, manifest version, and HTML page to show in DevTools.
panel.html Webpage to display in the custom panel in DevTools.
devtools.html A non-rendered HTML file run when DevTools is opened, to load the extension's JavaScript files.
background.js Service worker that sets up event listeners for communications between the inspected page and DevTools.
content_script.js Logic for the custom DevTools page. Prints a message to the console when the script is injected in the page. Adds a click event listener to the page that will send a message with mouse-click position in the inspected page.
devtools.js Logic for the custom DevTools page.
icon.png Icon to display on the tool's tab in the Activity bar of DevTools and in the More tools menu.
README.md Basic information for developers about how to use the sample.

Details are below.

manifest.json

The manifest file contains key/value pairs. The top-level keys are called members.

manifest.json is required. The manifest contains the following information about the extension:

  • The name of the extension.
  • The description of the extension.
  • The version of the extension.
  • The manifest version.
  • The HTML page to show in DevTools.
Member Description
name The name of the extension that will appear under edge://extensions/.
description The description of the extension that will be displayed under the name of the extension.
version The version of the extension that will appear next to the name of the extension.
manifest_version Determines the set of features that the extension will be using, such as service workers or network request modification. The current version is version 3. To learn more about this version and the differences with version 2, see Overview and timelines for migrating to Manifest V3.
devtools_page The path to an HTML file that's run every time DevTools is opened, and loads the extension's JavaScript files. This page isn't rendered in DevTools.
content_scripts The JavaScript or CSS files to use when the user opens specified webpages. See Content scripts in the Chrome docs.
background The JavaScript file that contains the extension's service worker, which acts as an event handler. See About extension service workers in the Chrome docs.
permissions The local device requires permissions to view its system memory capacity, since the script calls API for that.

manifest.json:

{
    "name": "Custom DevTools Tool",
    "description": "A DevTools extension interacting with the inspected page",
    "manifest_version": 3,
    "version": "1.0",
    "devtools_page": "devtools.html",
    "content_scripts": [{
        "matches": [
            "http://*/*",
            "https://*/*"
        ],
        "run_at": "document_idle",
        "js": [
            "content_script.js"
        ]
    }],
    "background": {
        "service_worker": "background.js"
    },
    "permissions": [
        "system.memory"
    ]
}

The permissions manifest member in manifest.json defines which permissions the extension requires from the user. Some permissions are needed to use certain extension APIs. The system-memory permission is required, in order to use the extension APIs. Specific APIs have associated permissions.

See also:

Code from manifest.json:

"content_scripts": [{
  "matches": [
    "http://*/*",
    "https://*/*"
  ],
  "run_at": "document_idle",
  "js": [
    "content_script.js"
  ]
}],
"background": {
    "service_worker": "background.js"
}

Keys within the "content_scripts" member:

Key Value
matches Specifies which pages this content script will be injected into.
run_at Indicates when the browser injects the script onto the page.
js The javascript files to be injected.

panel.html

panel.html is required. This is the webpage to display in the custom panel in DevTools.

panel.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <h2>Custom DevTools Tool</h2>

    <h3>Memory</h3>
    <div>
      <b>Available Memory Capacity:</b> <span id="availableMemoryCapacity"></span>
    </div>
    <div>
      <b>Total Memory Capacity:</b> <span id="totalMemoryCapacity"></span>
    </div>

    <h3>Send message from DevTools to inspected page</h3>
    <input type="button" id="sayHello" value="Say Hello">

    <h3>Send message from inspected page to DevTools</h3>
    <p>Click somewhere in the inspected webpage.</p>
    <div>
      <b>Coordinates:</b> <span id="youClickedOn"></span>
    </div>

  </body>
</html>

panel.html is referenced in the previous chrome.devtools.panels.create method call. This webpage contains the user interface of the custom tool's panel.

Code from panel.html:

a sayHello button and a youClickedOn label:

<input type="button" id="sayHello" value="Say Hello">

The above elements are used to demo the interaction between the inspected page, the DevTools panel, and the background service worker.

When the user clicks the sayHello button in the DevTools extension, it displays a greeting message in the inspected window.

When the user clicks anywhere in the inspected page, it will display a message to show the mouse-click position in the DevTools extension panel.

devtools.html

devtools.html is required. This is a non-rendered HTML file that's run when DevTools is opened, to load the extension's devtools.js file.

devtools.html matches the devtools_page member in the manifest file:

A <script> element loads the main JavaScript file that's used directly by panel.html. This devtools.html file isn't displayed in DevTools; only the panel.html file is displayed in DevTools.

devtools.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <script src="devtools.js"></script>
  </body>
</html>

In the manifest file (manifest.json), the devtools_page field specifies the above file (devtools.html). devtools.html, above, contains a <script> element that loads devtools.js.

background.js

background.js is a background service worker that sets up event listeners for communications between the inspected page and DevTools.

A background service worker is a script that the browser runs in a separate thread. This script has access to the Microsoft Edge extension APIs.

background.js:

let id = null;
const connections = {};

chrome.runtime.onConnect.addListener(devToolsConnection => {
    // Assign the listener function to a variable so we can remove it later
    let devToolsListener = (message, sender, sendResponse) => {
        if (message.name == "init") {
            id = message.tabId;
            connections[id] = devToolsConnection;
            // Send a message back to DevTools
            connections[id].postMessage("Connected!");
        }
    };

    // Listen to messages sent from the DevTools page
    devToolsConnection.onMessage.addListener(devToolsListener);

    devToolsConnection.onDisconnect.addListener(() => {
        devToolsConnection.onMessage.removeListener(devToolsListener);
    });
});

The above code connects the background service worker with the DevTools page. It listens to when the DevTools page connects, saves the connection, and sends a response back to the DevTools page.

This is useful when your background service worker is collecting data or performing tasks in the background that you want to be available in your DevTools extension.

See also:

content_script.js

content_script.js contains JavaScript that's injected into the inspected webpage (any webpage). This file does the following:

  • Prints a message to the DevTools Console when the page is clicked.
  • Listens for the page click event via an event listener.
  • Adds a click event listener to the webpage; clicking the page sends an event, caught by the event listener, which then sends a message to the WebView2 Runtime.

A content script runs in the context of the inspected webpage. In the same way that other scripts are loaded by the webpage, a content script has have access to the DOM and can change it.

This code prints a message to the console when the script is injected in the page. This code also adds a click event listener to the page that will send a message with mouse-click position in the inspected page by using the chrome.runtime.sendMessage API.

content_script.js:

document.addEventListener("click", (event) => {
  chrome.runtime.sendMessage({
      click: true,
      xPosition: event.clientX + document.body.scrollLeft,
      yPosition: event.clientY + document.body.scrollTop
    },
    response => {
      console.log("Received response", response);
    }
  );
});

See also:

devtools.js

devtools.js contains logic for the custom DevTools page.

devtools.js does the following:

  1. Creates a new Custom tool tab and panel in DevTools.

  2. When the tool is displayed (panel.onShown listener), the availableMemoryCapacity and totalMemoryCapacity elements are retrieved from the DOM.

  3. Sets a timer to run code every second after the panel is shown.

  4. When the timer fires, the chrome.system.memory.getInfo method is used to retrieve the available and total memory capacity of the device and these values are displayed in the corresponding DOM elements.

devtools.js:

let availableMemoryCapacity;
let totalMemoryCapacity;
let youClickedOn;

chrome.devtools.panels.create("Custom", "icon.png", "panel.html", panel => {
    // code invoked on panel creation
    panel.onShown.addListener( (extPanelWindow) => {
        // memory
        availableMemoryCapacity = extPanelWindow.document.querySelector('#availableMemoryCapacity');
        totalMemoryCapacity = extPanelWindow.document.querySelector('#totalMemoryCapacity');
        // 2-way message sending
        let sayHello = extPanelWindow.document.querySelector('#sayHello');
        youClickedOn = extPanelWindow.document.querySelector('#youClickedOn');
        sayHello.addEventListener("click", () => {
            // show a greeting alert in the inspected page
            chrome.devtools.inspectedWindow.eval('alert("Hello from the DevTools extension!");');
        });
    });
});

// Update Memory display
setInterval(() => {
    chrome.system.memory.getInfo((data) => {
        if (availableMemoryCapacity) {
            availableMemoryCapacity.innerHTML = data.availableCapacity;
        }
        if (totalMemoryCapacity) {
            totalMemoryCapacity.innerHTML = data.capacity;
        }
    });
}, 1000);

// Send message from inspected page to DevTools
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    // Messages from content scripts should have sender.tab set
    if (sender.tab && request.click == true) {
        console.log('I am here!');
        if (youClickedOn) {
            youClickedOn.innerHTML = `(${request.xPosition}, ${request.yPosition})`;
        }
        sendResponse({
            xPosition: request.xPosition,
            yPosition: request.yPosition
        });
    }
});

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

// Relay the tab ID to the background service worker
backgroundPageConnection.postMessage({
    name: 'init',
    tabId: chrome.devtools.inspectedWindow.tabId
});

Code from devtools.js:

chrome.devtools.panels.create("Custom", "icon.png", "panel.html", panel => {
    // code invoked on panel creation
});

The create method has the following signature:

chrome.devtools.panels.create(
    title: string, // Tool tab's label in Activity bar.
    iconPath: string, // Icon to display in tool's tab.
    pagePath: string, // Webpage to display in tool's panel.
    callback: function // Code to run when tool is opened.
)

Code from devtools.js:

let availableMemoryCapacity;
let totalMemoryCapacity;

chrome.devtools.panels.create("Sample Panel", "icon.png", "panel.html", panel => {
    // code invoked on panel creation
    panel.onShown.addListener((extPanelWindow) => {
        availableMemoryCapacity = extPanelWindow.document.querySelector('#availableMemoryCapacity');
        totalMemoryCapacity = extPanelWindow.document.querySelector('#totalMemoryCapacity');
    });
});

setInterval(() => {
    chrome.system.memory.getInfo((data) => {
        if (availableMemoryCapacity) {
            availableMemoryCapacity.innerHTML = data.availableCapacity;
        }
        if (totalMemoryCapacity) {
            totalMemoryCapacity.innerHTML = data.capacity;
        }
    });
}, 1000);

devtools.js does the following:

  1. Uses the chrome.runtime.connect method to create a connection to the background service worker.

  2. Sends the inspected window tabId to the service worker by using the backgroundPageConnection.postMessage method.

  3. Adds event listeners to the sayHello button and youClickedOn label that's defined in the panel.html file.

When the user clicks the sayHello button, the DevTools extension runs a code snippet of alert("Hello from the DevTools Extension"); in the inspected window by invoking the eval() method of the inspected window chrome.devtools.inspectedWindow.

When the user clicks anywhere in the inspected window, the DevTools extension will receive a message, from the background service worker, with request.click == true and the mouse position information.

See also:

icon.png

icon.png is the icon to display on the tool's tab in the Activity bar of DevTools and in the More tools menu:

Icon file

README.md

README.md contains basic information for developers about how to use the sample.

See also

GitHub:

Chrome docs: