24.04.26
Isolated Previews for Embedded Dev Environments
Why embedded runtimes need previews on a product-owned isolated origin instead of the application origin.
An embedded development environment is incomplete until it can show the thing being built. The editor and terminal matter, but the preview is where the user sees whether the code worked.
For browser-first runtimes, previews are not just a UI detail. They are a
runtime feature. The browser does not let a worker bind to
localhost:3000, so the runtime has to provide a preview URL that feels
like a normal page without sharing the host application origin.
The problem with pretending there is a port
In a local dev environment, a command opens a port and the browser visits it. In an embedded browser runtime, there is no real network listener. The "server" may be a worker responding to HTTP-like requests inside the runtime.
That means the host page needs a bridge:
- A process reports that it is listening on a virtual port.
- The host creates a preview URL.
- An iframe or fetch call requests that URL.
- The runtime routes the request to the process.
- The response is returned to the browser.
The bridge should be invisible to the user. They should see the app, not the transport.
Why isolation matters
Remote preview tunnels are useful, but they are not the best default for embedded demos and tutorials. Product-owned isolated previews have practical advantages:
- Untrusted preview code does not run on the app or account origin.
- CSP is easier to reason about.
- Screenshots and tests can inspect previews through the runtime API.
- The preview URL can be stable and product-owned.
- The app does not need to expose a public tunnel for every visitor.
For documentation and customer demos, those details matter. The preview is part of your product surface, not a disposable external link.
Service Workers make browser previews possible
Verklet uses a Service Worker to route preview requests. The host page
loads a preview URL on preview.verklet.com. The preview Service Worker
and bridge forward that request into the runtime process that owns the
virtual port.
From the iframe's perspective, it loaded a normal URL. From the runtime's perspective, it received a request and returned a response. From the host product's perspective, the editor and terminal stay in the product while the preview runs on an isolated Verklet origin.
That shape is especially useful for frameworks that expect browser-like behavior: static assets, relative URLs, cookies, and fetch calls should resolve consistently inside the preview origin.
HMR and websockets add another layer
Simple HTTP previews are only the first step. Development servers often expect HMR, websocket-like behavior, and root-relative imports. A useful preview bridge has to normalize those paths and route runtime-owned connections through the same preview surface.
That is why preview support belongs in the runtime rather than in each tutorial or demo. The host app should not need a custom bridge for every framework.
Server-backed sessions should use the same UI
Isolated preview routing also matters when a session promotes to the server backend. The process may now run in a managed workspace, but the host product should still receive port events and render the preview in the same place.
The user does not care whether the response came from a browser worker or a server session. They care that the preview updates when the command is ready.
The preview is part of the contract
Embedded runtimes are often evaluated by feel. Does the code run? Does the terminal stream output? Does the preview update? Can the user reload without losing work?
Isolated previews are a large part of that feel. They make the runtime look less like a remote lab and more like a native part of the product without giving generated code the host application's origin. For tutorials, demos, agents, and browser IDEs, that is the point.