Skip to content

Electroview

Electroview is the browser-side SDK. Its primary job is to attach a typed RPC object to the webview’s encrypted loopback transport, with a native bridge as fallback.

Define A Shared Schema

An RPC schema has a bun side and a webview side. Requests have a typed parameter and response; messages are one-way payloads.

import type { RPCSchema } from "electrobun/view";
export type AppRPC = {
bun: RPCSchema<{
requests: {
add: {
params: { a: number; b: number };
response: { sum: number };
};
};
messages: {
rendererReady: { title: string };
};
}>;
webview: RPCSchema<{
requests: {
getDocumentTitle: {
params: {};
response: string;
};
};
messages: {
showStatus: { message: string };
};
}>;
};

Keep the schema in a module imported by both contexts. It contains types only and emits no runtime code.

Browser Side

Use Electroview.defineRPC() to provide handlers for the webview side, then pass the returned object to the constructor. Calls can use the local rpc variable immediately after construction.

import { Electroview, type RPCSchema } from "electrobun/view";
type AppRPC = {
bun: RPCSchema<{
requests: {
add: { params: { a: number; b: number }; response: { sum: number } };
};
messages: { rendererReady: { title: string } };
}>;
webview: RPCSchema<{
requests: {
getDocumentTitle: { params: {}; response: string };
};
messages: { showStatus: { message: string } };
}>;
};
const rpc = Electroview.defineRPC<AppRPC>({
maxRequestTime: 10_000,
handlers: {
requests: {
getDocumentTitle: () => document.title,
},
messages: {
showStatus: ({ message }) => console.log(message),
},
},
});
const view = new Electroview({ rpc });
const result = await rpc.request.add(
{ a: 9, b: 8 },
{ maxRequestTime: 5_000 },
);
rpc.send.rendererReady({ title: document.title });
console.log(result.sum);
void view;

maxRequestTime on defineRPC is the default request timeout in milliseconds. The optional second argument to one request overrides it; Infinity disables the timeout for that call.

Main-Process Side

The same schema is attached to a BrowserView or BrowserWindow with BrowserView.defineRPC():

import {
BrowserView,
BrowserWindow,
type RPCSchema,
} from "electrobun/main";
type AppRPC = {
bun: RPCSchema<{
requests: {
add: { params: { a: number; b: number }; response: { sum: number } };
};
messages: { rendererReady: { title: string } };
}>;
webview: RPCSchema<{
requests: {
getDocumentTitle: { params: {}; response: string };
};
messages: { showStatus: { message: string } };
}>;
};
const rpc = BrowserView.defineRPC<AppRPC>({
handlers: {
requests: {
add: ({ a, b }) => ({ sum: a + b }),
},
messages: {
rendererReady: ({ title }) => console.log("Ready", title),
},
},
});
const win = new BrowserWindow({
title: "Typed RPC",
url: "views://main/index.html",
rpc,
});
const title = await rpc.request.getDocumentTitle({});
rpc.send.showStatus({ message: `Loaded ${title}` });
void win;

The directions are deliberate:

  • bun.requests execute in the main process and are called by the webview.
  • bun.messages are received in the main process and sent by the webview.
  • webview.requests execute in the browser and are called by the main process.
  • webview.messages are received in the browser and sent by the main process.

Empty RPC

The constructor still requires an RPC object when the view has no application messages:

import { Electroview, type RPCSchema } from "electrobun/view";
type EmptyRPC = {
bun: RPCSchema<{ requests: {}; messages: {} }>;
webview: RPCSchema<{ requests: {}; messages: {} }>;
};
const rpc = Electroview.defineRPC<EmptyRPC>({
handlers: { requests: {}, messages: {} },
});
new Electroview({ rpc });

Importing the view SDK is not required merely to use preload-provided custom elements or draggable regions. Construct Electroview when the page needs the application RPC transport.

Carrot Invocation

view.carrots.invoke() sends a request through the configured host RPC. It is available only when the packaged host exposes the Carrot invocation handler.

import { Electroview, type RPCSchema } from "electrobun/view";
type EmptyRPC = {
bun: RPCSchema<{ requests: {}; messages: {} }>;
webview: RPCSchema<{ requests: {}; messages: {} }>;
};
const rpc = Electroview.defineRPC<EmptyRPC>({
handlers: { requests: {}, messages: {} },
});
const view = new Electroview({ rpc });
const result = await view.carrots.invoke<{ value: string }>(
"com.example.settings",
"read",
{ key: "theme" },
);
console.log(result.value);

Electrobun intentionally has no implicit browser-to-browser RPC. Route communication through the main process or use an explicit web transport.