Usage: Content Scripts
Relevant source files
The following files were used as context for generating this wiki page:The webext-bridge content script module provides the necessary infrastructure to facilitate communication between the isolated world of a web page (window context) and the privileged contexts of a web extension (like background, popup, or devtools). It acts as a crucial message broker, forwarding messages between these distinct environments.
This module is not automatically detected; it must be explicitly imported in your content script files. It handles the complexity of establishing a persistent connection to the background script and managing message passing with the page's main window context.
Sources: src/content-script.ts, CHANGELOG.md:12-13
Architecture Overview
The content script's architecture is centered around two primary communication channels, managed by a central EndpointRuntime.
-
Persistent Port to Background: A
persistent-portis established with the background script. This handles all communication with other parts of the extension (background, popup, options, devtools). This connection is designed to be resilient, automatically reconnecting if the background service worker is terminated and restarted.
Sources: src/content-script.ts:8, src/internal/persistent-port.ts:14-19 -
Post-Messaging with Window: Communication with the sandboxed
windowcontext (the web page the content script is injected into) is handled via thewindow.postMessageAPI. This requires explicit opt-in and namespace configuration for security.
Sources: src/content-script.ts:7, src/internal/post-message.ts:10
The following diagram illustrates the content script's role as a message router.
This diagram shows the Content Script acting as a central hub, using window.postMessage to talk to scripts on the page and a runtime.Port to talk to the background script, which in turn communicates with other extension parts.
Sources: src/content-script.ts:8-12, src/background.ts:142-177
Initialization and Setup
On initialization, the content-script module sets up its core components.
usePostMessaging('content-script'): Initializes thepostMessagehandler for communicating with thewindowcontext.createPersistentPort(): Creates a long-lived connection to the background script.createEndpointRuntime(...): Instantiates the main message handling and routing logic.
The endpointRuntime is configured with a routing function that determines where to send an outgoing message.
// src/content-script.ts:9-12
const endpointRuntime = createEndpointRuntime('content-script', (message) => {
if (message.destination.context === 'window') win.postMessage(message)
else port.postMessage(message)
})
This setup is illustrated by the following sequence diagram.
This diagram shows the sequence of creating the window message handler, the background port, and the central runtime that uses them.
Sources: src/content-script.ts:7-12
Message Routing
Inbound Messages
The content script listens for messages from both the window and the background script and forwards them to the endpointRuntime for processing.
- From
window: When a message arrives from a page script, the content script wraps it and passes it toendpointRuntime.handleMessage. Crucially, it hardcodes theorigin.contextto"window"to prevent scripts from spoofing their identity. - From
background: Messages from the extension's persistent port are directly passed toendpointRuntime.handleMessage.
This flow shows how messages from both sources are funneled into the same handler, with an added security step for messages originating from the web page.
Sources: src/content-script.ts:14-22, src/content-script.ts:24
Outbound Messages
The routing logic for outbound messages, defined during the endpointRuntime creation, is straightforward:
- If the message's destination context is
window, it's sent viawin.postMessage. - For any other destination (e.g.,
background,popup), it's sent through the persistent port to the background script for further routing.
Sources: src/content-script.ts:9-12
Communicating with the Host Page (window)
By default, communication between the content script and the host page's window is disabled. To enable it, you must call allowWindowMessaging with a unique namespace.
import { allowWindowMessaging } from 'webext-bridge/content-script';
// It's recommended to use a unique namespace to avoid conflicts
// with other extensions or scripts on the page.
allowWindowMessaging('my-app-namespace');
This function performs two actions:
win.setNamespace(nsps): Assigns the namespace to thepostMessagemodule. This is a mandatory step to prevent conflicts if multiple libraries are usingpostMessageon the same page.win.enable(): Flips a boolean flag to start allowingpostMessagecalls.
If setNamespace is not called, the library will throw an error to enforce this isolation.
Sources: src/content-script.ts:38-41, src/internal/post-message.ts:25-29, src/internal/post-message.ts:43-51
On the window side (i.e., in a script running on the web page), the setNamespace function must also be called with the same namespace string to establish the communication channel.
Sources: src/window.ts:18-21
API Reference
The content script module exports the following functions:
| Function | Description |
|---|---|
sendMessage | Sends a message to another extension context or the window. Returns a Promise that resolves with the response. |
onMessage | Registers a listener for incoming messages. |
openStream | Opens a persistent, namespaced communication Stream to another context. |
onOpenStreamChannel | Registers a listener for incoming stream requests on a specific channel. |
allowWindowMessaging | (Content Script Only) Enables and namespaces communication with the window context. Takes a unique namespace string as an argument. |
Sources: src/content-script.ts:38-43, src/internal/endpoint-runtime.ts:8-19, src/internal/stream.ts:146-163
Error Handling
If a message is sent from the content script to the window, but the recipient terminates (e.g., the page unloads) before replying, the sendMessage promise will not hang indefinitely. Instead, the content script will receive an error notification and end the transaction.
Specifically, if the persistent port connection to the background script fails for a message that originated from the window, the content script will post an error message back to the window to notify it of the failure.
Sources: src/content-script.ts:26-36