Web Quickstart
This page is the browser-only path. You get a running, pinging app with a
plain Node + browser setup — no Android AAR, no iOS embedding, no bare CLI
incantations. It is the fastest way to feel the model before you wire a host
(see End-to-End Quickstart for the native side).
The repo ships a runnable reference web app at
examples/web/.
This quickstart starts it and then shows the few lines that make the ping work.
1. Prerequisites
Section titled “1. Prerequisites”- Node ≥ 22 (the repo uses modern ESM +
import.meta.env). - A desktop browser.
- A clone of the framework repo (the dev loop builds the core bundle for you).
git clone https://github.com/anderscan/ekroohcd ekroohnpm install2. Run the web dev loop
Section titled “2. Run the web dev loop”npm run devThis starts two things together:
- the loopback Bare backend — it builds
core/main.core.tsand runs it on the Bare runtime, serving a WebSocket protocol socket on port 8080 (the web transport defaults tows://localhost:8080in dev), and - the Vite dev server for
examples/web.
Open the localhost URL Vite prints (typically http://localhost:5173). You are
looking at the reference app, served cross-origin from the Vite dev server and
connected to the loopback backend.
No
esbuildorbareCLI steps are required —npm run devbuilds the core bundle and restarts the Bare process on change.
3. See it ping
Section titled “3. See it ping”The reference app already talks to the backend. Click Ping on the page and
you’ll see PING ok: hello — a full web → WebSocket → worklet → web round-trip,
with no native host involved.
4. How the ping is wired (minimal)
Section titled “4. How the ping is wired (minimal)”If you want to see the smallest version of the same call, this is the whole client surface:
import { MessageType, createPluginBus, createProtocolMessenger,} from '@ekrooh/bare/core';import { healthEvents } from '@ekrooh/bare/plugins/health/events';import { createWebSocketTransport } from '@ekrooh/bare/transports';
// In browser dev the transport defaults to ws://localhost:8080.const transport = await createWebSocketTransport();
const messenger = createProtocolMessenger((request, payload) => { transport.send(MessageType.ENVELOPE, request, payload);});const bus = createPluginBus(messenger);transport.subscribe((message) => messenger.handleIncoming(message.header));
const [err, result] = await bus.invoke(healthEvents.health.ping('hello'));console.log( err ? `PING failed: ${err.message}` : `PING ok: ${result?.message}`,);createWebSocketTransport() takes no arguments here: in dev,
import.meta.env.DEV is true, so it points at the loopback backend for you. On
device the page is served by the loopback server, so the socket defaults to the
page’s own origin — you only ever pass an explicit { url } in browser dev.
5. Render the result
Section titled “5. Render the result”@ekrooh/bare is not a UI framework — it owns the wire protocol, plugin
kernel, and transports, not your DOM. Render result with whatever UI layer you
already use. The reference app uses lit-html + nanostores; the full rendering
contract (one root render(), useStore bindings, cache() for routes,
teardown) is in Web Rendering.
Next steps
Section titled “Next steps”- Add your own capability: Authoring a Plugin and the call-a-native-function tutorial.
- Go cross-platform: End-to-End Quickstart for the Android/iOS host side.