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
- Decide whether Craft's long-term mobile story is WebView-only, or WebView plus an embedded JS runtime for native-UI apps.
- 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".
- Keep the bridge protocol transport-agnostic in the meantime, so this stays possible.