Frontend Development 12 min read

Developing Chrome DevTools Extensions and Supporting Technologies in San DevTools

The article expands the San DevTools technical analysis by detailing how to build Chrome DevTools extensions—defining a devtools page, creating panels, and debugging them—while also covering supporting technologies such as Yarn‑workspace monorepos, TypeScript path aliases, a lightweight middleware server, message‑batching bridges, and custom SVG icon components.

Baidu App Technology
Baidu App Technology
Baidu App Technology
Developing Chrome DevTools Extensions and Supporting Technologies in San DevTools

This article continues the "San DevTools Technical Analysis" series and introduces two main topics: DevTools extension development and several other valuable techniques used in the San DevTools project.

DevTools Extension Development

The article explains that the term "Chrome Extension" refers to a web‑technology based add‑on that enhances browser functionality. A DevTools extension is a special kind of Chrome extension that adds new panels or sidebars to Chrome DevTools and can interact with the inspected page. It can access DevTools APIs such as devtools.inspectedWindow , devtools.network , and devtools.panels .

Implementation consists of three simple steps:

Define devtools_page in manifest.json to point to an HTML file.

Create an HTML file that only loads a JavaScript entry script.

Use chrome.devtools.panels.create to create a custom panel (multiple panels are allowed).

Example manifest:

{
    "devtools_page": "devtools.html"
}

Example HTML skeleton:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>DevTools</title>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
  </head>
  <body>
    <script src="/js/devtools.js"></script>
  </body>
</html>

Creating a panel:

chrome.devtools.panels.create(
    'San',
    '/icons/logo128.png',
    'panel.html'
);

The article also lists debugging methods for the different parts of an extension: Content Script (F12 or right‑click → Inspect), DevTools Panel (right‑click inside the panel → Inspect), and Background page (chrome://extensions → Inspect background page).

Other Technologies

Monorepo Project Management

San DevTools uses a monorepo layout managed by Yarn workspaces. The repository contains a packages folder with sub‑packages such as shared and backend . A simplified tree view:

san-devtools
├── packages
│   ├─ shared
│   │   ├─ src
│   │   └─ package.json
│   └─ backend
│       ├─ src
│       └─ package.json
├── tsconfig.json
├── .eslintrc
├── node_modules
└── package.json

Relevant package.json snippets:

{
  "scripts": {
    "start": "yarn workspace san-devtools start",
    "build:standalone": "yarn workspace san-devtools build",
    "start:extensions": "yarn workspace extensions start",
    "build:extensions": "yarn workspace extensions build"
  },
  "workspaces": ["packages/*"],
  "files": ["packages"]
}

Module Resolution

Path aliases such as @shared and @backend are configured in tsconfig.json and a webpack‑like config:

{
  "paths": {
    "@backend/*": ["packages/backend/src/*"],
    "@frontend/*": ["packages/frontend/src/*"],
    "@shared/*": ["packages/shared/src/*"]
  }
}
const baseConfig = {
  resolve: {
    alias: {
      '@backend': resolve('backend/src/'),
      '@shared': resolve('shared/src/'),
      '@frontend': resolve('frontend/src/')
    }
  }
};

Simple Middleware Server

A lightweight server class demonstrates how to register middleware functions and handle requests:

class Server {
  constructor(options) {
    this._middlewares = [];
    this.use(...);
    this.createServer();
  }
  createServer() {
    this._server = http.createServer((req, res) => {
      this._requestHandler(req, res, err => { /* ... */ });
    });
  }
  _requestHandler(req, res, errorHandler) {
    let idx = 0;
    const middlewares = this._middlewares;
    const firstHandler = middlewares[idx];
    run(firstHandler);
    function next() {
      idx++;
      if (idx < middlewares.length) run(middlewares[idx]);
    }
    function run(fn) { fn(req, res, next); }
  }
  use(fn) { this._middlewares.push(fn); }
};

Message Batching

The Bridge class batches events using requestAnimationFrame to reduce send frequency. Key methods include send , _emit , _nextSend , and internal queues for batching and receiving.

const BATCH_DURATION = 100;
export default class Bridge extends EventEmitter {
  constructor(wall) { super(); this.wall = wall; /* ... */ }
  send(event, payload) { /* push to _batchingQueue, schedule flush */ }
  _emit(message) { /* handle string, chunk, or normal messages */ }
  _nextSend() { /* send via wall, then requestAnimationFrame */ }
}

Iconfont Integration

A custom san-custom-icon component renders SVG icons defined in icons.ts . The component uses a type prop to select the appropriate path data.

<template>
  <svg xmlns="http://www.w3.org/2000/svg" class="{{['Icon', className]}}" width="24" height="24" viewBox="0 0 1024 1024">
    <template s-for="item in paths">
      <path fill="currentColor" d="{{item}}" />
    </template>
  </svg>
</template>
<script>
import icons from './icon.ts';
export default {
  initData() { return { className: '' }; },
  computed: {
    paths() { return icons[this.data.get('type')] || null; }
  }
};
</script>
<style lang="less">
.Icon { width: 1em; height: 1em; fill: currentColor; }
</style>

Usage example:

<san-custom-icon type="start-record" />

The article concludes with a brief overview of the San ecosystem and a list of reference links.

frontend developmentMiddlewareMonorepoChrome ExtensioniconfontdevtoolsMessage Batching
Baidu App Technology
Written by

Baidu App Technology

Official Baidu App Tech Account

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.