host:ipc
The host:ipc module provides inter-process communication (IPC) between your Deno application and window renderers (WebViews).
Overview
IPC enables bidirectional messaging:
- Deno to Renderer: Send data to windows using
sendToWindow() - Renderer to Deno: Receive events using
windowEvents()or callbacks
Types
IpcEvent
Event received from a renderer:
interface IpcEvent { /** Window ID that sent the event */ windowId: string; /** Channel name for the event */ channel: string; /** Event payload data */ payload: unknown; /** Event type for window system events */ type?: "close" | "focus" | "blur" | "resize" | "move";}Callback Types
/** Callback for all IPC events */type IpcEventCallback = (event: IpcEvent) => void;
/** Callback for channel-specific handlers */type ChannelCallback = (payload: unknown, windowId: string) => void;Sending Messages
sendToWindow(windowId, channel, payload?)
Send a message to a specific window’s renderer. The message is received by window.host.on(channel, callback) in the WebView.
import { sendToWindow } from "host:ipc";
// Send data to a specific windowawait sendToWindow("main-window", "update", { count: 42 });
// Send a simple notificationawait sendToWindow("main-window", "refresh");broadcast(windowIds, channel, payload?)
Send a message to multiple windows simultaneously:
import { broadcast } from "host:ipc";
// Send to multiple windowsawait broadcast( ["main", "settings", "preview"], "theme-changed", { theme: "dark" });Receiving Events
Using Async Generators
windowEvents()
Async generator that yields all window events:
import { windowEvents } from "host:ipc";
for await (const event of windowEvents()) { console.log(`[${event.windowId}] ${event.channel}:`, event.payload);
if (event.type === "close") { console.log("Window closed"); break; }}windowEventsFor(windowId)
Filter events for a specific window:
import { windowEventsFor } from "host:ipc";
// Only process events from the main windowfor await (const event of windowEventsFor("main")) { console.log("Main window event:", event.channel);}channelEvents(channel)
Filter events for a specific channel:
import { channelEvents } from "host:ipc";
// Only process "button-click" eventsfor await (const event of channelEvents("button-click")) { console.log("Button clicked in window:", event.windowId);}Using Callbacks
onEvent(callback)
Register a callback for all IPC events. Returns an unsubscribe function:
import { onEvent } from "host:ipc";
const unsubscribe = onEvent((event) => { console.log(`Event: ${event.channel} from ${event.windowId}`);});
// Later, to stop listening:unsubscribe();onChannel(channel, callback)
Register a callback for events on a specific channel:
import { onChannel } from "host:ipc";
const unsubscribe = onChannel("user-action", (payload, windowId) => { console.log(`User action from ${windowId}:`, payload);});
// Later, to stop listening:unsubscribe();Low-Level Receive
recvWindowEvent()
Receive the next event (blocking). Returns null when the channel closes:
import { recvWindowEvent } from "host:ipc";
const event = await recvWindowEvent();if (event) { console.log(`Received: ${event.channel} from ${event.windowId}`);}Renderer API
In your WebView (renderer), use the window.host API to communicate with Deno:
Sending from Renderer
// Send a message to Denowindow.host.send("button-click", { buttonId: "submit" });
// Send with no payloadwindow.host.send("refresh");Receiving in Renderer
// Listen for messages from Denowindow.host.on("update", (payload) => { console.log("Received update:", payload);});
// Remove listenerwindow.host.off("update", handler);Complete Example
Deno Side (main.ts)
import { createWindow } from "host:window";import { sendToWindow, onChannel } from "host:ipc";
// Create the main windowconst win = await createWindow({ title: "My App", width: 800, height: 600,});
// Listen for button clicks from the rendereronChannel("button-click", async (payload, windowId) => { const { buttonId } = payload as { buttonId: string }; console.log(`Button ${buttonId} clicked in ${windowId}`);
// Send response back to the window await sendToWindow(windowId, "button-response", { success: true, message: `Processed ${buttonId}`, });});
// Listen for window closeonChannel("close", async (_, windowId) => { console.log(`Window ${windowId} requested close`);});Renderer Side (index.html)
<!DOCTYPE html><html><body> <button id="submit">Submit</button> <div id="status"></div>
<script> const submitBtn = document.getElementById("submit"); const status = document.getElementById("status");
// Send click event to Deno submitBtn.addEventListener("click", () => { window.host.send("button-click", { buttonId: "submit" }); });
// Receive response from Deno window.host.on("button-response", (payload) => { status.textContent = payload.message; }); </script></body></html>Patterns
Request-Response Pattern
import { sendToWindow, onChannel } from "host:ipc";
// Deno: Handle requests and send responsesonChannel("fetch-data", async (payload, windowId) => { const { requestId, query } = payload as { requestId: string; query: string };
// Process the request const result = await fetchFromDatabase(query);
// Send response with matching requestId await sendToWindow(windowId, "fetch-response", { requestId, data: result, });});Multi-Window Sync
import { broadcast, onEvent } from "host:ipc";
// Track all window IDsconst windows = new Set<string>();
onEvent((event) => { windows.add(event.windowId);
// Broadcast state changes to all windows if (event.channel === "state-change") { broadcast( Array.from(windows), "state-update", event.payload ); }});Event Routing
import { onChannel } from "host:ipc";
// Route different channels to different handlersonChannel("auth", handleAuth);onChannel("data", handleData);onChannel("settings", handleSettings);
function handleAuth(payload: unknown, windowId: string) { // Handle authentication events}
function handleData(payload: unknown, windowId: string) { // Handle data events}
function handleSettings(payload: unknown, windowId: string) { // Handle settings events}