ReviewOS

craft-native/craft

feat(runtime): rendering native views still requires a WKWebView purely to execute JavaScript

#328
Closed glennmichael123 opened this 10 days ago ·
10 days ago

Summary

If Craft grows a native view tree, the WKWebView is no longer rendering anything — it is only there to execute JavaScript. That is an expensive way to get a JS engine, and it brings a rendering pipeline, a networking stack and a lifecycle that a native-UI app has no use for.

The shape of the problem

A native-UI framework hosted by Craft runs its own logic in JS: component state, effects, event handlers, data fetching. Today the only place to run that is the web view. So an app with zero HTML in it would still boot a full browser engine, and every view mutation would cross the JS ↔ WebView ↔ bridge boundary instead of JS ↔ bridge.

React Native made the same call early and never shipped a WebView in the core: JavaScriptCore first, then Hermes, with the bridge (now JSI) between JS and the native view layer.

What this would look like

A JS runtime Craft can host with no web view attached:

  • iOS — JavaScriptCore is in the SDK, no binary size cost, and is what React Native used for years.
  • Android — JavaScriptCore or QuickJS. QuickJS is small and embeds cleanly in a Zig host.
  • Desktop — the same runtime keeps one execution model across platforms rather than two.

The bridge protocol does not need to change shape; it needs a second transport that is "to the JS runtime" rather than "to the web view".

Why file it now

It only matters once native views exist, so it is not urgent. It is worth deciding early because the answer shapes the bridge: a protocol designed around postMessage to a web view is awkward to retarget at an embedded engine, and a protocol designed for an embedded engine works for both.

Ask

  1. Decide whether Craft's long-term mobile story is WebView-only, or WebView plus an embedded JS runtime for native-UI apps.
  2. If the latter, prototype JavaScriptCore on iOS behind the existing bridge interface — no view work, just "run this JS outside a WebView and let it talk to native".
  3. Keep the bridge protocol transport-agnostic in the meantime, so this stays possible.
10 days ago

Implemented on main.

Craft now has an opt-in mobile native renderer that executes compiled STX without a browser view:

  • iOS runs the bundle in JavaScriptCore and renders UIKit controls;
  • Android runs the same bundle in JavaScriptSandbox and renders Android views;
  • the STX runtime talks through globalThis.__stxNativeBridge, keeping the bundle independent of the platform transport;
  • the existing web renderer remains the default;
  • missing bundles or unsupported Android runtime capabilities produce explicit errors and never fall back to WKWebView/WebView;
  • real simulator/emulator fixtures assert that native routes contain no web view while state, events, navigation, images, scrolling, and accessibility continue to work.

The contract and prerequisites are documented in docs/guides/native-stx.md. The core implementation landed across d8ecca4c through 3daf5c83. The remaining native view-tree work (batched node operations, full layout, and a recycling list) stays tracked in #327.

Sign in to comment on this issue.