Frontend Development 14 min read

Developing Chrome Extensions with Browser‑Extension‑Kit: Architecture and Messaging

Building a Chrome extension that redirects network requests illustrates the complexities of message passing across isolated contexts, and the article shows how the browser‑extension‑kit framework abstracts routing, state management, and RxJS integration to streamline development, reduce boilerplate, and improve maintainability for React‑based popups and background scripts.

DaTaobao Tech
DaTaobao Tech
DaTaobao Tech
Developing Chrome Extensions with Browser‑Extension‑Kit: Architecture and Messaging

Chrome extensions are widely used to improve productivity (e.g., 1Password, Adblock, React Developer Tools). This article shows how to build a custom extension that redirects network requests, explains the challenges of message passing between isolated execution contexts, and introduces a framework (browser‑extension‑kit) that simplifies development.

Example scenario : redirect a request (similar to XSwitch) from an original URL to a user‑provided URL, enabling online debugging with a local webpack‑dev‑server.

In the popup UI, users input the original and new URLs. The code connects to the background script via chrome.runtime.connect() and posts messages:

// popup.js
import React from 'react';
const port = chrome.runtime.connect();
export const App = () => {
  return (
    <>
原始 URL:
port.postMessage({ originalUrl: e.target.value })} />
新 URL:
port.postMessage({ newUrl: e.target.value })} />
);
};

The background script listens for the connection, stores the URLs, and uses chrome.webRequest.onBeforeRequest to perform the redirect:

// background.js
let originalUrl = '';
let newUrl = '';
chrome.runtime.onConnect.addListener(port => {
  port.onMessage.addListener(message => {
    if (message.originalUrl) {
      originalUrl = message.originalUrl;
    } else if (message.newUrl) {
      newUrl = message.newUrl;
    }
  });
});
chrome.webRequest.onBeforeRequest.addListener(request => {
  if (!originalUrl || !newUrl || request.url !== originalUrl) {
    return;
  }
  return { redirectUrl: newUrl };
}, {}, ['blocking']);

Real‑world extensions involve multiple contexts (background, popup, content‑script, page‑script, devtools). Managing message flow across these isolated environments quickly becomes complex, leading to repetitive boilerplate and hard‑to‑maintain code.

Problems identified :

Missing framework support for common modules (monitoring, logging, auth, message routing).

Message‑related pitfalls: distinguishing internal vs. external messages, connection lifetimes, unclear routing paths, size limits, serialization issues (circular references, large objects).

New development approach : Use browser‑extension‑kit to encapsulate message handling, state management, and cross‑context communication. Developers write business logic in isolated classes that inherit from framework base classes.

Example of a background class using RxJS and decorators:

import { from } from 'rxjs';
import { Background } from 'browser-extension-kit/background';
import { subject, observable } from 'browser-extension-kit';

export default class MyBackground extends Background {
  constructor() {
    super();
    this.myObservable1$.subscribe(data => {
      // handle data
    });
    this.on('messageID', message => {
      // handle message
    });
  }

  @subject('uniqueID')
  private mySubject = new rxjs.Subject
();

  @observable.popup
  private myObservable1$ = rxjs.from(...).pipe(rxjs.shareReplay(1));

  @observable(['background', 'popup'])
  private myObservable2$ = rxjs.concat(rxjs.from(...), this.mySubject).pipe(rxjs.shareReplay(1));
}

Popup UI written with React can now use hooks provided by the kit:

import React, { useCallback } from 'react';
import { useMessage, usePostMessage } from 'browser-extension-kit/popup';

const App = () => {
  const active = useMessage('MyBackground::active$', null);
  const port = usePostMessage();
  const toggleActive = useCallback(() => {
    port.background('MyBackground::active', !active);
  }, [port, active]);
  return (
active: {active}
click me
);
};
export default App;

The framework automatically creates a central port hub, subscribes each context to a ReplaySubject so that messages sent before a context loads are replayed, and provides a dispatcher in the background to route messages to the appropriate context.

Conclusion : While routing all messages through the background adds some overhead, the trade‑off yields cleaner code and easier maintenance. The kit currently targets React‑based UI (popup, devtools) and leaves domain‑specific features (monitoring, auth) to the application. Install with npm i browser-extension-kit -S or yarn add browser-extension-kit and explore the API on GitHub.

JavaScriptreactChrome ExtensionRxJSBrowser Extension KitMessage Passing
DaTaobao Tech
Written by

DaTaobao Tech

Official account of DaTaobao Technology

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.