vercel-labs / vercel-labs/native

allow scene (canvas-first) apps to configure the zero://app asset root

Open
#102 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Zig
Stars
7.7k
Forks
314
Avg merge
5h
Merged PRs (30d)
13

Description

Environment

  • native-sdk v0.4.2
  • macOS aarch64
  • Zig 0.16.0

What happens

NativeSdkAssetSchemeHandler and configureWithRootPath: exist in the
macOS host and back the zero://app asset scheme, but the asset root is
only ever configured as a side effect of a main-webview loading an
assets-source URL. A UiApp scene (canvas-first) app never performs that
main-webview assets-source load — the whole point of a scene app is that
the primary surface is the native canvas, not a webview. As a result, any
scene-declared webview pane (UiApp.Options.web_panes, a .webview shell
view anchored into the canvas layout) has no working asset root and cannot
load zero://app/... content.

What I expected

I expected a scene app to be able to opt into the zero://app asset root
independently of whether it ever loads a main webview — e.g. because it
hosts one or more secondary webview panes that need to load bundled static
assets (HTML/CSS/JS/images) from the app bundle.

What we did instead (workaround)

Without a configured asset root, the only way we found to serve static
content into a scene-declared webview pane is to spawn a loopback HTTP
server via the effects channel (fx.spawn sh -c "python3 -m http.server ... --bind 127.0.0.1 ...") and point the pane at
http://127.0.0.1:<port>/..., adding that origin to
security.navigation.allowed_origins. This works (verified end-to-end,
including clean teardown of the spawned process on app exit), but it's
extra moving parts — a subprocess, a startup race between the pane's first
navigation and the server binding (we handle it with a reload_token
bump-until-loaded pattern), and a port to manage — for what should be
static, bundle-local content.

Repro / code pointers

(Line numbers from the v0.4.2 npm-distributed sources.)

  • Host-side plumbing that already exists:
    NativeSdkAssetSchemeHandler (src/platform/macos/appkit_host.m:628),
    configureWithRootPath:entryPath:spaFallback: (appkit_host.m:6201).
  • The only caller of configureWithRootPath: is the main-webview
    loadSource: path (appkit_host.m:9207, source kind = assets), which
    UiApp scene apps never exercise. Per-window handlers are created only
    inside ensureMainWebViewForWindowId: (appkit_host.m:6633, stored at
    :6668); scene/child webview creation reuses them via
    assetHandlerForWindowId: (appkit_host.m:6691, consumed at :7314) —
    so in a canvas-first app the lookup returns nil and the pane's
    WKWebViewConfiguration gets no zero scheme handler at all.
  • Repro app: spike/canvas-web/ — a UiApp shell hosting a WKWebView
    pane via UiApp.Options.web_panes, a scene-declared .webview shell
    view parented to the canvas and anchored to a panel's layout frame. The
    pane currently loads content from the loopback server described above
    rather than zero://app.

Suggested direction

We're building an image-optimization app where the comparison canvas is a
WKWebView pane (a pure-native tiled canvas tops out around 26–32 fps at
full-canvas coverage in our measurements, well short of a webview pane's
~119 fps sustained; see our companion perf report). Static assets
(comparison-page HTML/CSS/JS) are exactly the kind of bundle-local content
zero://app seems designed for. A manifest field (e.g. under .shell or
per-webview-pane config) or a RunOptions/Runtime API call to set the
asset root explicitly — without requiring a main-webview assets-source
load to happen first — would let scene apps drop the loopback server
entirely for static content. If there's a reason the asset root is tied to
the main-webview load specifically (security scoping, bundle path
resolution timing, etc.), we'd be glad to hear the constraint — happy to
help test an API shape against spike/canvas-web/.


Related: #101, #103 — the companion issues referenced above

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the existing handler and configuration flow in src/platform/macos/appkit_host.m, especially NativeSdkAssetSchemeHandler, configureWithRootPath:entryPath:spaFallback:, ensureMainWebViewForWindowId:, assetHandlerForWindowId:, and the loadSource: caller. Reproduce the current behavior with spike/canvas-web and trace how the scene pane obtains its WKWebViewConfiguration. Done means a canvas-first scene can explicitly configure zero://app for bundled assets without a main-webview assets-source load, while preserving the existing main-webview path.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, zig
Domain
desktop, web-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.