webext-bridge

repository·main·Indexed 20 days ago

https://github.com/serversideup/webext-bridge

A lightweight library providing a simple and consistent API for sending and receiving messages between different parts of a web extension, such as background scripts, content scripts, popups, devtools, options, and windows. It abstracts browser-specific differences for cross-platform compatibility across Chrome, Firefox, Safari, and Edge, and supports type-safe protocols via a ProtocolMap interface.

Tokens
11K
Snippets
41
Records
54
Agent score
55%

What's inside webext-bridge

  1. Introduction to webext-bridge

    main

    Overview

    webext-bridge provides a simple, consistent, and production-ready API for messaging between different parts of a web extension. It abstracts away the complexities and browser-specific differences involved in cross-context communication.

    Supported Contexts

    You can send messages between various extension contexts, including:

    • background
    • content-script
    • devtools
    • popup
    • options
    • window

    This package is used in production by Bugflow.

  2. What is webext-bridge?

    main

    webext-bridge is a lightweight library designed to simplify messaging within web extensions. It provides a consistent API for sending and receiving messages across various extension contexts, helping to keep data in sync without the typical complexity of the standard WebExtension messaging APIs.

    Supported contexts include:

    • background
    • content-script
    • devtools
    • popup
    • options
    • window
  3. Extension Communication Contexts

    main

    Messages in webext-bridge are routed between specific execution contexts. When using the library, you import the specific context module required for your current environment using the pattern: import { ... } from 'webext-bridge/{context}'.

    The available contexts are:

    • content-script
    • popup
    • options
    • background
    • devtools
    import { ... } from 'webext-bridge/content-script'; // Example import pattern
  4. Routing messages to DevTools or Content Scripts

    main

    When using sendMessage(msgId, data, destination) or openStream(channelId, initialData, destination), you can target specific environments as the destination:

    • From content-script to devtools: Specifying devtools as the destination will auto-route the payload to the inspecting DevTools page if it is open and listening. If DevTools are not open, the message is queued and delivered once the user opens DevTools and switches to your extension's DevTools panel.
    • From devtools to content-script: Specifying content-script as the destination will auto-route the message to the inspected window's top content-script page. If the page is currently loading, the message is queued and delivered once the page is ready and listening.
    // Example of specifying a destination
    sendMessage('my-msg-id', { foo: 'bar' }, 'devtools');
    sendMessage('my-msg-id', { foo: 'bar' }, 'content-script');
  5. How sendMessage() and onMessage() work

    main

    The core communication in webext-bridge relies on two primary methods: sendMessage() to dispatch data and onMessage() to listen for it.

    sendMessage()

    Used to send a message to a specific destination. It accepts three parameters:

    1. messageId: A unique identifier for the message (e.g., an uppercase string or enum).
    2. data: The JSON payload to be sent.
    3. destination: The target context (e.g., background, popup, or content-script@{tabId}).

    onMessage()

    Used to listen for incoming messages. It accepts two parameters:

    1. messageId: The ID of the message to listen for (must match the sender's messageId).
    2. callback: An asynchronous function that handles the message. The callback receives an object containing metadata and the payload.
  6. Security considerations for window context messaging

    main

    When using webext-bridge to communicate with window contexts, be aware that calling allowWindowMessaging(namespace) in a content script unlocks the window context in that tab.

    Unlike standard chrome.runtime APIs, webext-bridge does not automatically restrict which websites can send messages to your extension via the window context. Any webpage can attempt to send messages using the webext-bridge protocol if they know your namespace.

    Best Practices:

    1. Origin Validation: Before calling allowWindowMessaging, verify that the page's window.location.origin matches your expected trusted domains.
    2. Sender Verification: Treat window messaging with the same caution as window.postMessage. Always verify the sender of a message before performing critical actions or returning sensitive data.
  7. Advantages of using webext-bridge over built-in messaging

    main

    Using webext-bridge provides several improvements over standard chrome.runtime messaging APIs:

    • Targeted Scoping: You import from specific entry points (webext-bridge/popup, webext-bridge/background, etc.), ensuring messages are sent to and handled by the correct parts of the extension without scoping issues.
    • Cleaner Code: Instead of using massive switch/case statements inside a single onMessage listener, you can bind specific actions directly to handler functions using onMessage(action, handler).
    • Cross-Platform: The code is designed to work across Firefox, Chrome, Safari, and Edge, providing a unified API for multi-platform browser extensions.
    // Comparison: Built-in messaging requires manual switch/case logic
    browser.runtime.onMessage.addListener( ( request, sender, sendResponse ) => {
        switch( request.action ){
            case "ACTION":
                runAction( request.data ).then( sendResponse );
                return true;
            break; 
        }
    } );
  8. Requirement for the Background Script context

    main

    The background context is a critical requirement for the library to function. webext-bridge uses the background/event context as a staging area for all messages.

    Crucial Requirement: You must load webext-bridge in your background/event page, even if your extension does not explicitly use the background script for sending or receiving messages.

    Warning: If webext-bridge is not available in the background page, attempting to send a message from any other context will fail silently.

  9. How webext-bridge communication works

    main

    Browser extensions function like a collection of microservices (popup, background, content scripts, etc.) that need to communicate. Standard browser messaging lacks direct control over message routing and often leads to complex switch statements and callback chains.

    webext-bridge solves this by providing:

    1. Scoped Messaging: You can explicitly define which context a message is sent to.
    2. Type-safe Protocols: Ensures messages follow a predictable structure.
    3. Efficient Handling: Simplifies the logic for receiving and routing incoming messages.
  10. Enable window messaging for security

    main

    By default, messaging to or from the window context is restricted for security. To enable it, you must perform two steps within a content script and the target window context:

    1. In the content script: Call allowWindowMessaging(<namespace: string>) to unlock message routing for a specific namespace.
    2. In the window context: Call setNamespace(<namespace: string>) using the same namespace string used in step 1.

    Using a specific namespace ensures that webext-bridge correctly identifies which messages belong to your extension, preventing collisions if multiple extensions are present on the same page.

    // 1. In your content script:
    await allowWindowMessaging('my-unique-namespace');
    
    // 2. In the target window context:
    await setNamespace('my-unique-namespace');