Browse packages

Package · v0.28.0

webview

Standard library webview

Native webview for JavaScript runtimes.

What is @rcompat/webview?#

A cross-runtime module for creating native desktop applications with web technologies. Uses the system's native webview (WebKit on macOS/Linux, WebView2 on Windows) for lightweight, fast rendering. Works with Bun and Deno.

Note: Node.js is unsupported; constructing a Webview there throws.

Installation#

Linux system requirements#

The Linux x64 sidecar uses WebKitGTK 6.0, GTK 4, and libsoup 3. Install the runtime packages supplied by your distribution before starting a webview:

bash
# Arch Linux
sudo pacman -S webkitgtk-6.0

# Debian and Ubuntu
sudo apt install libgtk-4-1 libwebkitgtk-6.0-4

# Fedora
sudo dnf install gtk4 webkitgtk6.0

WebKitGTK 4.0, GTK 3, and libsoup 2 do not satisfy this requirement and must not be substituted with ABI symlinks. The package provides Linux x64 and arm64 sidecars.

bash
npm install @rcompat/webview
bash
pnpm add @rcompat/webview
bash
yarn add @rcompat/webview
bash
bun add @rcompat/webview

Usage#

Basic webview#

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

const webview = new Webview({ platform });

webview.navigate("https://example.com");
webview.run();

Set HTML content directly#

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

const webview = new Webview({ platform });

webview.html = `
  <!DOCTYPE html>
  <html>
    <body>
      <h1>Hello from Webview!</h1>
    </body>
  </html>
`;

webview.run();

Custom window size#

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

const webview = new Webview({ platform });

webview.size = {
    width: 800,
    height: 600,
    hint: 0, // 0=none, 1=min, 2=max, 3=fixed
};

webview.navigate("https://example.com");
webview.run();

Debug mode#

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

// enable developer tools
const webview = new Webview({ platform, debug: true });

webview.navigate("https://example.com");
webview.run();

Server with webview in worker#

Create a local server and open it in a webview using a worker for non-blocking operation:

worker.ts

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

const webview = new Webview({ platform });

webview.navigate("http://localhost:8181");
webview.run();

app.ts

ts
import http from "@rcompat/http";

const headers = { "Content-Type": "text/html" };
const html = `
  <html>
    <body>
      <h1>Desktop App</h1>
      <a href="https://github.com">GitHub</a>
    </body>
  </html>
`;

http.serve(() => new Response(html, { headers }), {
  host: "localhost",
  port: 8181,
});

// Bun
new Worker("worker.ts");

// Deno
new Worker(new URL("worker.ts", import.meta.url).href, { type: "module" });

API Reference#

Webview#

ts
import Webview from "@rcompat/webview";
import platform from "@rcompat/webview/default";
import type {
  Init, Size, SizeHint, Webview as WebviewContract,
} from "@rcompat/webview";

const init: Init = { platform };
const webview: WebviewContract = new Webview(init);

Constructor Options#

Property Type Default Description
platform BunFile | string — Platform binary (required)
debug boolean false Enable developer tools

Properties#

Property Type Description
html string | undefined Read or set the latest HTML content
size Required<Size> Read the effective size or set partial dimensions

Size Object#

Property Type Default Description
width number 1280 Window width in pixels
height number 720 Window height in pixels
hint 0-3 0 0=none, 1=min, 2=max, 3=fixed

All size properties are optional when assigning webview.size; omitted values use the defaults shown above. Reading webview.size returns a snapshot, so mutating that object does not resize the native window. Assign a new partial size object to resize it. SizeHint is the union 0 | 1 | 2 | 3.

Methods#

Method Description
navigate(url) Navigate to a URL
run() Start the webview event loop (blocking)
destroy() Idempotently terminate and clean up the webview

run() destroys the native handle after the event loop exits. When running in a worker, destruction posts the message "destroyed"; main-thread use does not require postMessage to exist.

Platform Exports#

Auto-detect the current platform:

ts
import platform from "@rcompat/webview/default";

Or replace that import with exactly one explicit target:

ts
import platform from "@rcompat/webview/darwin-arm64"; // macOS ARM
ts
import platform from "@rcompat/webview/darwin-x64"; // macOS Intel
ts
import platform from "@rcompat/webview/linux-arm64"; // Linux ARM64
ts
import platform from "@rcompat/webview/linux-x64"; // Linux x64
ts
import platform from "@rcompat/webview/windows-x64"; // Windows x64

Only the six platform paths shown above are exported. Platform selection is kept explicit so Bun and Deno compilers can include the selected sidecar.

Compiling to Executable#

Bun#

bash
bun build app.ts worker.ts --compile --minify

Deno#

bash
deno compile --no-check --include worker.ts app.ts

Cross-Compilation#

Generate platform-specific builds for distribution:

build.ts

ts
import fs from "@rcompat/fs";
import runtime from "@rcompat/runtime";

const prefix = "--platform=";
const platform = runtime.args
  .find(argument => argument.startsWith(prefix))
  ?.slice(prefix.length) ?? "default";

await fs.ref(import.meta.dirname).join("worker.ts").write(`
  import platform from "@rcompat/webview/${platform}";
  import Webview from "@rcompat/webview";

  const webview = new Webview({ platform });
  webview.navigate("http://localhost:8181");
  webview.run();
`);

Build for Linux from macOS#

bash
# Bun
bun build.ts --platform=linux-x64
bun build app.ts worker.ts --compile --target=bun-linux-x64 --minify

# Deno
deno -A build.ts --platform=linux-x64
deno compile --no-check --include worker.ts --target=x86_64-unknown-linux-gnu app.ts

Examples#

Desktop app with graceful shutdown#

ts
// app.ts
import http from "@rcompat/http";

const html = `
  <!DOCTYPE html>
  <html>
    <body>
      <h1>My Desktop App</h1>
      <button onclick="alert('Clicked!')">Click Me</button>
    </body>
  </html>
`;

const server = await http.serve(
  () => new Response(html, { headers: { "Content-Type": "text/html" } }),
  { host: "localhost", port: 8181 }
);

// Bun
const worker = new Worker("worker.ts");

// Deno
const worker = new Worker(new URL("worker.ts", import.meta.url).href, {
    type: "module",
});

// graceful shutdown when webview closes
worker.addEventListener("message", (event) => {
  if (event.data === "destroyed") {
    server.stop();
  }
});

Static HTML app#

ts
import platform from "@rcompat/webview/default";
import Webview from "@rcompat/webview";

const webview = new Webview({ platform, debug: true });

webview.size = { width: 400, height: 300, hint: 3 }; // Fixed size

webview.html = `
  <!DOCTYPE html>
  <html>
    <head>
      <style>
        body {
          font-family: system-ui;
          display: flex;
          align-items: center;
          justify-content: center;
          height: 100vh;
          margin: 0;
          background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
          color: white;
        }
      </style>
    </head>
    <body>
      <h1>Hello, Desktop!</h1>
    </body>
  </html>
`;

webview.run();

Supported Platforms#

Platform Architecture Export
macOS ARM64 darwin-arm64
macOS x64 darwin-x64
Linux ARM64 linux-arm64
Linux x64 linux-x64
Windows x64 windows-x64

Cross-Runtime Compatibility#

Runtime Supported
Bun ✓
Deno ✓
Node.js Unsupported (constructor throws)

License#

MIT

Contributing#

See CONTRIBUTING.md in the repository root.