RPC messaging library for the VS Code extension platform. Makes the communication between your VS Code extension and its webviews much simpler.
- Send notifications or requests from an extension to a view, a view group, or broadcast to all registered views
- Send notifications or requests from a view to another view, a view group, or the host extension
- Typed API —
RequestType<P, R>andNotificationType<P>enforce matching parameter and result types on both sides - Sync and async request/notification handlers
- Request cancellation
- Automatically unregisters views on dispose
- Configurable logging
Install only what each side needs:
| Package | Install in | Purpose |
|---|---|---|
vscode-messenger |
Extension host | Messenger class, view registration, diagnostic API |
vscode-messenger-webview |
Webview script | Messenger class for webview, createCancellationToken |
vscode-messenger-common |
Shared module | NotificationType, RequestType, HOST_EXTENSION, BROADCAST |
Tip: Keep all NotificationType / RequestType declarations in a shared TypeScript module imported by both the extension and the webview. The same method string and parameter/result types must match on both ends.
import * as vscode from 'vscode';
import { Messenger } from 'vscode-messenger';
import { NotificationType, RequestType } from 'vscode-messenger-common';
const messenger = new Messenger();
// Register a webview view (or use registerWebviewPanel for WebviewPanel)
messenger.registerWebviewView(webviewView);
// Define message types — declare once, import on both sides
const colorSelectType: NotificationType<string> = { method: 'colorSelected' };
const availableColorsType: RequestType<string, string[]> = { method: 'availableColor' };
const colorModifyType: NotificationType<string> = { method: 'colorModify' };
// Handle a notification from the webview
messenger.onNotification(colorSelectType, (color: string) => {
vscode.window.activeTextEditor?.insertSnippet(new vscode.SnippetString(`#${color}`));
});
// Handle a request from the webview and return a result
messenger.onRequest(availableColorsType, (_params: string) => {
return ['020202', 'f1eeee', 'a85b20', 'daab70', 'efcb99'];
});
// Send a notification to all views of a given type
messenger.sendNotification(colorModifyType, { type: 'webview', webviewType: 'calicoColors.colorsView' }, 'clear');
// Send a request to a view and await the result
const selectedColor = await messenger.sendRequest(
{ method: 'getSelectedColor' },
{ type: 'webview', webviewType: 'calicoColors.colorsView' },
''
);import { Messenger } from 'vscode-messenger-webview';
import { HOST_EXTENSION } from 'vscode-messenger-common';
import { colorModifyType, availableColorsType, colorSelectType } from './shared/message-types';
const messenger = new Messenger(); // acquireVsCodeApi() is called automatically
// Handle notifications from the extension
messenger.onNotification(colorModifyType, (action: string) => {
if (action === 'clear') clearColors();
if (action === 'add') addColor();
});
messenger.start(); // required — starts listening for incoming messages
// Send a request to the host extension
const colors = await messenger.sendRequest(availableColorsType, HOST_EXTENSION, '');
// Send a notification to the host extension
messenger.sendNotification(colorSelectType, HOST_EXTENSION, 'a85b20');Note:
messenger.start()must be called before any messages can be received. Forgetting it causes all incoming messages to be silently dropped.
| Participant | How to construct | Use for |
|---|---|---|
| Host extension | HOST_EXTENSION |
Targeting the extension from a webview |
| Webview by type | { type: 'webview', webviewType: '...' } |
All instances of a view type |
| Webview by id | returned by registerWebviewView / registerWebviewPanel |
One specific instance |
| Broadcast | BROADCAST |
All registered views (notifications only) |
// Extension side — pass any CancellationToken
const cts = new vscode.CancellationTokenSource();
const result = await messenger.sendRequest(longOpType, target, params, cts.token);
cts.cancel();
// Webview side — bridge an AbortSignal
import { createCancellationToken } from 'vscode-messenger-webview';
const ctrl = new AbortController();
const result = await messenger.sendRequest(longOpType, HOST_EXTENSION, params, createCancellationToken(ctrl.signal));
ctrl.abort('timeout');A webview receives a broadcast only when registered with broadcastMethods listing the method:
// Extension: opt the view in to specific broadcast methods
messenger.registerWebviewView(view, { broadcastMethods: [refreshType.method] });
// Either side: broadcast to all opted-in views
messenger.sendNotification(refreshType, BROADCAST);The companion VS Code Messenger Developer Tool extension visualizes live message traffic — requests, responses, and notifications — between the extension host and its webviews. To enable it, expose messenger.diagnosticApi() from your extension's activate return value:
import { Messenger, type MessengerDiagnostic } from 'vscode-messenger';
const messenger = new Messenger();
export function activate(context: vscode.ExtensionContext): MessengerDiagnostic {
// ... register views, handlers, etc.
return messenger.diagnosticApi();
}Open the devtool with Developer: Open vscode-messenger devtools from the Command Palette.
See the devtools README for full setup instructions, DiagnosticOptions, the event schema, and troubleshooting.
The calico-colors example demonstrates a complete extension with a WebviewView and a WebviewPanel sharing a single Messenger instance, typed message definitions in a shared module, broadcast usage, and diagnostic API integration.