Full-stack dev environment

Run real web and mobile dev servers in the browser with a terminal and a live preview, no backend.

Lifo can host a real front-end dev server — Vite, Expo, whatever — entirely in a browser tab, with a terminal and a live preview. No cloud dev environment, no container: the dev server runs in the box, and a service worker streams its output into an iframe with HMR intact.

This guide wires up a terminal and a live preview using @lifo-sh/ui.

npm install @lifo-sh/core @lifo-sh/ui

A web dev server (Vite) with live preview

<div id="terminal" style="height: 320px"></div>
<div id="preview" style="height: 460px"></div>
import { Sandbox, ServiceWorkerBridge } from "@lifo-sh/core";
import { Terminal, PreviewBrowser } from "@lifo-sh/ui";

// 1. Boot a box with a terminal attached.
const term = new Terminal(document.getElementById("terminal")!);
const sandbox = await Sandbox.create({ terminal: term, cwd: "/home/user" });

// 2. Route in-VM ports through a service worker (served at /sw.js).
const bridge = new ServiceWorkerBridge(sandbox.kernel.portRegistry);
await bridge.connect("/sw.js", "/");

// 3. Scaffold and start a Vite app. npm and npx are real inside the box.
sandbox.commands.run(
  "npx create-vite@latest app -- --template react && " +
    "cd app && npm install && npm run dev",
  { onStdout: (c) => term.write(c), onStderr: (c) => term.write(c) },
);

// 4. Show it live. Vite's dev server listens on 5173 inside the box.
new PreviewBrowser(document.getElementById("preview")!, { bridge, port: 5173 });

The preview renders the running app, and edits trigger HMR through the bridge — the same loop you'd have locally. Your user can type in the terminal too; it's a real shell on the box.

Note

Live previews need the Lifo service worker at /sw.js with a Service-Worker-Allowed: / header. See Live previews.

Mobile: Expo (React Native Web)

The same shape runs a mobile app. Expo's web target is a dev server like any other, so scaffold with create-expo-app, add the web deps, and preview it:

sandbox.commands.run(
  "npx create-expo-app@latest app --template blank && cd app && " +
    "npx expo install react-dom react-native-web && npm run web",
  { onStdout: (c) => term.write(c) },
);
// Expo's web dev server listens on 8081 inside the box.
new PreviewBrowser(document.getElementById("preview")!, { bridge, port: 8081 });

Both SDK 54 and 57 run unmodified. For a physical device, a tunnel exposes the in-VM port to Expo Go.

Persisting and restoring the project

Enable persistence so the disk survives reloads, or snapshot the whole box to move it elsewhere:

const sandbox = await Sandbox.create({ terminal: term, persist: true });
// …later…
const image = await sandbox.fs.exportSnapshot(); // tar.gz of the project

Next