Usage: Background Script
Relevant source files
The following files were used as context for generating this wiki page:The webext-bridge background script serves as the central message broker and connection manager for the entire extension. It is designed to reliably route messages between all other extension contexts, such as content scripts, popups, options pages, and devtools. Its primary responsibility is to listen for incoming connections, maintain a registry of active endpoints, and forward messages to their intended destinations.
This hub-and-spoke architecture simplifies communication logic for other contexts, as they only need to know how to talk to the background script, which then handles the complexity of locating and delivering messages to the correct recipient. The background script also manages the lifecycle of connections, handling unexpected disconnects (like a tab closing or a service worker terminating) and notifying relevant parties to prevent indefinite waits for responses.
Architecture Overview
The background script acts as a singleton hub. All other extension contexts establish a persistent connection to it. This model allows any context to communicate with any other context without needing to manage direct connections.
Sources: src/background.ts, src/internal/persistent-port.ts
System Components
The following diagram illustrates the central role of the background script.
This diagram shows various extension contexts establishing a connection with the central background script, which then uses PortMessage to communicate back.
Sources: src/background.ts:281, src/internal/persistent-port.ts:121-128
Key Internal Components
The background script relies on several key data structures and modules to manage its state.
| Component | Description | Source File |
|---|---|---|
connMap | A Map that stores all active port connections, keyed by a unique endpoint identifier string (e.g., content-script@123). | src/background.ts:16 |
pendingResponses | A delivery logger that tracks messages awaiting a reply. This is used to notify senders if a recipient disconnects before replying. | src/background.ts:15, src/internal/delivery-logger.ts |
endpointRuntime | The core message-handling engine that provides sendMessage, onMessage, and handleMessage functionalities. | src/background.ts:150, src/internal/endpoint-runtime.ts |
oncePortConnectedCbs | A Map of callbacks to be executed once a specific endpoint connects. This handles cases where a message is sent to a lazy-loading script. | src/background.ts:17 |
onceSessionEndCbs | A Map of callbacks to be executed when a specific connection session terminates. | src/background.ts:18 |
Connection Management
The background script's lifecycle revolves around managing connections from other contexts via browser.runtime.onConnect.
Sources: src/background.ts:281-352
Connection Handshake
When a context (e.g., a content script) wants to communicate, it creates a persistent port to the background script. The port's name contains encoded arguments, including a unique fingerprint for the session and an optional endpointName.
- A client context calls
createPersistentPort, which in turn callsbrowser.runtime.connect. The connection arguments are encoded into the port's name. - The background script's
onConnectlistener fires. decodeConnectionArgsis used to parse thefingerprintandendpointNamefromincomingPort.name.- The new connection (
portandfingerprint) is stored inconnMapusing theendpointNameas the key. - Any pending callbacks for this endpoint in
oncePortConnectedCbsare executed.
The following sequence diagram illustrates this process.
Disconnection Handling
When a port disconnects (e.g., a tab is closed), the onDisconnect listener is triggered. The background script performs cleanup to ensure system stability:
- It removes the connection from
connMap, but only if the fingerprint matches. This check prevents a race condition where a new connection from the same endpoint is established before the old one's disconnect event is processed. - It finds all messages in
pendingResponsesthat were sent to the disconnected client and marks them as failed. - It notifies the original senders of those messages that the session has terminated, preventing them from waiting indefinitely.
Sources: src/background.ts:303-325, src/background.ts:327-335
Message Routing
The core function of the background script is to route InternalMessage objects between endpoints. This logic is encapsulated within the callback provided to createEndpointRuntime.
Sources: src/background.ts:152-243
Routing Flow
When endpointRuntime.handleMessage is called with a message:
- The sender and destination endpoints are resolved into standardized string formats using
formatEndpoint. Forwindowcontexts, they are resolved to their correspondingcontent-scriptendpoint. - The destination tab ID is inferred from the sender's tab ID if not explicitly provided.
- The system checks
connMapto see if the destination endpoint is currently connected. - If connected: The message is immediately forwarded to the recipient's port using
PortMessage.toExtensionContext. A delivery receipt is logged. - If not connected:
- If the sender is another context (not background), it is notified that the message is
undeliverableand that the system will notify it when the destination becomesdeliverable. - If the sender is the background script itself, the delivery is queued via
oncePortConnectedto be sent as soon as the destination connects.
- If the sender is another context (not background), it is notified that the message is
This flow is visualized below.
Message Types
Communication between clients and the background script uses two categories of messages defined in port-message.ts.
| Category | Direction | Types | Description - |
| RequestMessage | Client → Background | sync, deliver | sync is sent on reconnect to sync state. deliver is used to send a standard InternalMessage. - |
| StatusMessage | Background → Client | undeliverable, deliverable, delivered, incoming, terminated | These messages inform the client about the state of its sent messages or the state of other endpoints. - |
Sources: src/internal/port-message.ts:9-41
Exported API
Like other contexts, the background script itself can send and receive messages using the API exported from src/background.ts. This allows the background script to be an active participant in communication, not just a passive router.
| Function | Description |
|---|---|
sendMessage | Sends a message to a specific destination and returns a promise that resolves with the reply. |
onMessage | Registers a listener to handle incoming messages with a specific ID. |
openStream | Opens a persistent, channel-based communication stream to another endpoint. |
onOpenStreamChannel | Registers a listener to handle incoming requests to open a stream on a specific channel. |
Sources: src/background.ts:354-356, src/internal/endpoint-runtime.ts:18-32, src/internal/stream.ts:110-149
Example: Sending a message from Background
When sending a message from the background script to a context that can have multiple instances (like a content script), the target tab must be specified.
// src/background.ts
// This is a conceptual example of how the exported API would be used.
import { sendMessage } from 'webext-bridge/background'
async function notifyTab(tabId: number) {
const response = await sendMessage(
'ping',
{ message: 'Hello from background!' },
`content-script@${tabId}`,
);
console.log('Received response in background:', response);
}
A TypeError is thrown if a message is sent from the background to content-script or devtools without specifying a tabId.
Sources: src/background.ts:154-161
Summary
The background script is the architectural cornerstone of webext-bridge. It provides a centralized, robust, and reliable system for managing connections and routing messages between disparate parts of a web extension. By abstracting away the complexities of port management, connection lifecycles, and message delivery, it enables developers to build complex, communicative extensions with a simple and consistent API. Its ability to handle offline or lazy-loaded contexts by queuing messages further enhances its reliability, making it a powerful tool for extension development.