Skip to content

Commit 7d63f56

Browse files
committed
Deliver behavioral parity plan
1 parent 99d1ee4 commit 7d63f56

13 files changed

Lines changed: 1762 additions & 175 deletions

README.md

Lines changed: 196 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,114 @@
1-
# WebUI Zig Manual Port
1+
# WebUI Zig (Manual Port)
22

3-
This repository now uses a Zig-only active runtime and build graph.
3+
A Zig-first WebUI runtime with typed RPC, generated JS/TS bridge code, native-webview-first execution, and browser fallback.
44

5-
## What changed
5+
## Status
66

7-
- No `@cImport`
8-
- No active C/C++/ObjC compilation in runtime/library build paths
9-
- JS helper asset processing/minification is pure Zig (no `zig cc` path)
10-
- Idiomatic Zig API surface:
11-
- `App`
12-
- `Window`
13-
- `Event`
14-
- `RpcRegistry`
15-
- `DispatcherMode`
16-
- `BridgeOptions`
17-
- `TransportMode`
7+
This project is actively usable, but it is not yet full behavioral parity with upstream `webui.c`.
188

19-
Legacy native and script sources are archived in:
9+
Current parity snapshot (`zig build parity-local`):
10+
- `total=40`
11+
- `implemented=36`
12+
- `partial=4`
13+
- `missing=0`
2014

21-
- `upstream_snapshot/webui-2.5.0-beta.4/`
15+
Current partial areas:
16+
- `window.visual.transparency`
17+
- `window.visual.frameless`
18+
- `window.visual.corner_radius`
19+
- `server.tls_toggle`
2220

23-
## Build
21+
See `parity/status.json` and `docs/upstream_file_parity.md` for details.
22+
23+
## Highlights
24+
25+
- Zig-only active runtime/library build path (`@cImport` and runtime C/C++/ObjC compilation removed).
26+
- Idiomatic API (`App`, `Window`, `Service`, `RpcRegistry`, `WindowStyle`, typed events).
27+
- Comptime RPC registration via `pub const rpc_methods = struct { ... }`.
28+
- Generated JS client + TypeScript declarations.
29+
- `sync`, `threaded`, and `custom` RPC dispatch modes.
30+
- Native-webview-first runtime with browser fallback.
31+
- Extensive third-party browser discovery/search paths across Linux/macOS/Windows.
32+
33+
## Quick Start
2434

2535
```bash
2636
zig build
2737
zig build test
2838
zig build examples
29-
zig build parity-report
30-
zig build parity-local
31-
zig build os-matrix
32-
zig build bridge
3339
zig build run
34-
zig build run -Dexample=fancy_window
3540
```
3641

37-
`zig build run` runs all examples by default (`-Dexample=all`) with a native-webview-first configuration and browser fallback enabled.
42+
Run one example:
3843

39-
Available `-Dexample=` values:
40-
- `minimal`
41-
- `call_js_from_zig`
42-
- `call_zig_from_js`
43-
- `serve_folder`
44-
- `vfs`
45-
- `public_network`
46-
- `multi_client`
47-
- `chatgpt_api`
48-
- `custom_web_server`
49-
- `react`
50-
- `frameless`
51-
- `fancy_window`
52-
- `translucent_rounded`
53-
- `text_editor`
54-
- `minimal_oop`
55-
- `call_js_oop`
56-
- `call_oop_from_js`
57-
- `serve_folder_oop`
58-
- `vfs_oop`
59-
- `all` (batch mode with short auto-timeout per example)
44+
```bash
45+
zig build run -Dexample=translucent_rounded
46+
```
47+
48+
Force runtime mode:
6049

61-
`zig build os-matrix` compiles the library and examples across Linux/macOS/Windows targets with static and dynamic linkage combinations.
50+
```bash
51+
zig build run -Dexample=fancy_window -Drun-mode=webview
52+
zig build run -Dexample=fancy_window -Drun-mode=browser
53+
```
54+
55+
List all build steps/options:
56+
57+
```bash
58+
zig build -l
59+
zig build -h
60+
```
6261

63-
### Build Flags
62+
## Build Flags
6463

65-
- `-Ddynamic=true`
66-
- Builds `webui` as a shared library (`.so`/`.dylib`/`.dll`) instead of a static archive.
67-
- This changes artifact linkage format only; it does not enable/disable runtime features by itself.
68-
- `-Denable-tls=true`
69-
- Sets TLS-enabled default at compile time for runtime options.
70-
- `-Denable-webui-log=true`
71-
- Sets WebUI logging-enabled default at compile time for runtime options.
72-
- `-Dminify-embedded-js=true` (default: `true`)
73-
- Processes embedded runtime helper JS (used by runtime-generated bridge strings) using pure Zig tooling.
74-
- `-Dminify-written-js=true` (default: `false`)
75-
- Processes written runtime helper JS assets (used by file-writing bridge generation paths) using pure Zig tooling.
64+
| Flag | Default | Effect |
65+
|---|---:|---|
66+
| `-Ddynamic=true` | `false` | Build/install `webui` as a shared library (`.so`/`.dylib`/`.dll`) instead of static archive. |
67+
| `-Denable-tls=true` | `false` | Enables TLS defaults in runtime options/API state. |
68+
| `-Denable-webui-log=true` | `false` | Enables runtime log defaults. |
69+
| `-Dminify-embedded-js=true` | `true` | Minifies embedded runtime helper JS asset at build time. |
70+
| `-Dminify-written-js=true` | `false` | Minifies written runtime helper JS output artifact. |
71+
| `-Dexample=<name>` | `all` | Selects example used by `zig build run`. |
72+
| `-Drun-mode=webview|browser` | `webview` | Chooses native-webview path or browser-mode path in examples. |
73+
| `-Dtarget=<triple>` | host | Cross-compiles the library/examples for another target. |
7674

77-
These compile-time values are exported by the module as:
75+
Exported compile-time values:
7876
- `webui.BuildFlags.dynamic`
7977
- `webui.BuildFlags.enable_tls`
8078
- `webui.BuildFlags.enable_webui_log`
81-
82-
## Usage
79+
- `webui.BuildFlags.run_mode`
80+
81+
## Build Steps
82+
83+
- `zig build` (default install)
84+
- `zig build test`
85+
- `zig build examples`
86+
- `zig build run`
87+
- `zig build bridge`
88+
- `zig build runtime-helpers`
89+
- `zig build vfs-gen`
90+
- `zig build parity-report`
91+
- `zig build parity-local`
92+
- `zig build os-matrix`
93+
94+
## API Overview
95+
96+
Top-level exports (`src/root.zig`):
97+
- `App`, `Window`, `Service`
98+
- `Event`, `EventKind`
99+
- `RpcRegistry`, `RpcOptions`, `DispatcherMode`
100+
- `WindowStyle`, `WindowControl`, `WindowCapability`
101+
- `BridgeOptions`, `TransportMode`
102+
- `ScriptOptions`, `ScriptEvalResult`
103+
- `TlsOptions`, `TlsInfo`
104+
105+
Core flow:
106+
1. Declare `pub const rpc_methods` as a comptime struct of functions.
107+
2. Initialize `Service` or `App + Window`.
108+
3. Show `html`, `file`, or `url` content.
109+
4. Run app loop and exchange RPC/raw messages.
110+
111+
### Minimal Service Example
83112

84113
```zig
85114
const std = @import("std");
@@ -89,6 +118,10 @@ pub const rpc_methods = struct {
89118
pub fn ping() []const u8 {
90119
return "pong";
91120
}
121+
122+
pub fn add(a: i64, b: i64) i64 {
123+
return a + b;
124+
}
92125
};
93126
94127
pub fn main() !void {
@@ -101,101 +134,114 @@ pub fn main() !void {
101134
.browser_fallback_on_native_failure = true,
102135
.auto_open_browser = true,
103136
},
104-
.window = .{
105-
.title = "Demo",
106-
.style = .{
107-
.frameless = true,
108-
.transparent = true,
109-
.corner_radius = 12,
110-
},
111-
},
137+
.window = .{ .title = "WebUI Zig Demo" },
138+
.rpc = .{ .dispatcher_mode = .threaded },
112139
});
113140
defer service.deinit();
114141
115-
const bridge_js = webui.Service.generatedClientScriptComptime(rpc_methods, .{});
116-
const bridge_dts = webui.Service.generatedTypeScriptDeclarationsComptime(rpc_methods, .{});
117-
_ = bridge_js;
118-
_ = bridge_dts;
142+
try service.show(.{
143+
.html =
144+
"<!doctype html><html><head><meta charset=\"utf-8\"/>" ++
145+
"<script type=\"module\" src=\"/webui_bridge.js\"></script></head>" ++
146+
"<body><button id=\"b\">Ping</button><pre id=\"out\"></pre>" ++
147+
"<script>document.getElementById('b').onclick=async()=>{" ++
148+
"const p=await webuiRpc.ping();const s=await webuiRpc.add(20,22);" ++
149+
"document.getElementById('out').textContent=`${p} ${s}`;};</script></body></html>",
150+
});
119151
120-
try service.show(.{ .html = "<html><body>Hello</body></html>" });
121152
try service.run();
122-
_ = try service.control(.maximize);
123153
}
124154
```
125155

126-
## Notes
127-
128-
- `zig build bridge` generates `zig-out/share/webui/webui_bridge.js`.
129-
- `zig build bridge` also generates `zig-out/share/webui/webui_bridge.d.ts`.
130-
- `zig build runtime-helpers` prepares helper assets:
131-
- `zig-out/share/webui/runtime_helpers.embed.js` (default minified)
132-
- `zig-out/share/webui/runtime_helpers.written.js` (default non-minified)
133-
- Declare RPC methods in app entrypoints as `pub const rpc_methods = struct { ... };`.
134-
- The same `rpc_methods` constant should be used for:
135-
- service initialization: `webui.Service.init(allocator, rpc_methods, ...)`
136-
- compile-time JS generation: `webui.Service.generatedClientScriptComptime(rpc_methods, ...)`
137-
- compile-time TS generation: `webui.Service.generatedTypeScriptDeclarationsComptime(rpc_methods, ...)`
138-
- The typed RPC bridge can also be emitted at runtime from `Service.rpcClientScript()` / `RpcRegistry.generatedClientScript()`.
139-
- Runtime helper JS strings are exported as:
140-
- `webui.runtime_helpers_js` (embedded/default variant)
141-
- `webui.runtime_helpers_js_written` (written-file variant)
142-
- Friendly shortcuts:
143-
- `App.initDefault(allocator)`
144-
- `App.window()` / `App.windowWithTitle(title)`
145-
- `Window.show(.{ .html = ... | .file = ... | .url = ... })`
146-
- `Window.applyStyle(WindowStyle)`
147-
- `Window.currentStyle()`
148-
- `Window.lastWarning()` / `Window.clearWarning()`
149-
- `Window.control(WindowControl)`
150-
- `Window.setCloseHandler(handler, context)`
151-
- `Window.capabilities()`
152-
- `Window.bindRpc(RpcStruct, RpcOptions)`
153-
- `Window.rpcClientScript(BridgeOptions)`
154-
- `Window.rpcTypeDeclarations(BridgeOptions)`
155-
- `Service.init(allocator, rpc_methods, options)`
156-
- `Service.generatedClientScriptComptime(rpc_methods, options)`
157-
- `Service.generatedTypeScriptDeclarationsComptime(rpc_methods, options)`
158-
- `Service.lastWarning()` / `Service.clearWarning()`
159-
- `webui.process_signals.install()` / `webui.process_signals.stopRequested()` for immediate `Ctrl+C` shutdown handling
160-
- Comptime bridge generation is available via `RpcRegistry.generatedClientScriptComptime(RpcStruct, options)`.
161-
- TypeScript declarations are available via:
162-
- `RpcRegistry.generatedTypeScriptDeclarations(options)`
163-
- `RpcRegistry.generatedTypeScriptDeclarationsComptime(RpcStruct, options)`
164-
- `RpcRegistry.writeGeneratedTypeScriptDeclarations(path, options)`
165-
- Third-party browser-side JS libraries are preserved as static assets.
166-
- Manual desktop smoke checklist: `docs/manual_gui_checklist.md`.
167-
168-
## Runtime Transport
169-
170-
- Browser fallback runtime now serves:
171-
- bridge script route (default `/webui_bridge.js`)
172-
- RPC route (default `/webui/rpc`)
173-
- local content (`showHtml` / `showFile`) over `http://127.0.0.1:<port>/`
174-
- Browser control APIs:
175-
- `Window.browserUrl()` returns the local browser-render URL.
176-
- `Window.openInBrowser()` explicitly opens the window content in a discovered browser.
177-
- `Window.openInBrowserWithOptions(webui.BrowserLaunchOptions)` overrides default browser launch policy per call.
178-
- `AppOptions.browser_launch.prompt_policy` supports `quiet_default` and `browser_default` presets.
179-
- Window parity routes (used by generated bridge helpers):
180-
- `POST /webui/window/control` (`minimize|maximize|restore|close|hide|show`)
181-
- `GET|POST /webui/window/style`
182-
- If `transport_mode = .native_webview`, `browser_fallback_on_native_failure=true` (default) keeps browser rendering available.
183-
- Window style/control calls are routed through backend abstractions first, then browser emulation when native behavior is unavailable.
184-
- When a native backend cannot satisfy a requested style/control on the current target/runtime, WebUI emits warning events/logs, sets `lastWarning()`, and falls back to emulation when enabled.
185-
- Browser fallback launch tracks spawned browser PID when available and terminates it on `shutdown()`.
186-
- On POSIX, browser fallback is launched as a direct child process and assigned its own process group; shutdown kills the full browser process group.
187-
- If PID tracking is unavailable on a platform/launcher path, frontend lifecycle heartbeat remains the fallback close mechanism.
188-
- Browser catalog includes at least:
189-
- Firefox, Chrome, Edge, Chromium, Yandex, Brave, Vivaldi (Windows/macOS/Linux)
190-
- Epic (Windows/macOS/Linux catalog entry)
191-
- Safari (Windows/macOS/Linux catalog entry; active availability varies by OS)
192-
- Opera (Windows/macOS/Linux catalog entry)
193-
- Dispatcher modes:
194-
- `sync`: invoke RPC on request thread
195-
- `threaded`: request thread submits RPC to worker thread queue (poll-driven condition waits)
196-
- `custom`: user callback receives function name + invoker + parsed args
197-
- Bridge/rpc routes and namespace are configurable via `BridgeOptions`.
198-
- Network transport model:
199-
- one listener thread accepts and handles HTTP requests
200-
- threaded RPC dispatch hands off execution to a worker thread queue
201-
- listener thread uses condition-variable polling waits for worker completion and then writes the response
156+
## Typed RPC + Bridge Generation
157+
158+
All RPC methods are declared once at comptime:
159+
160+
```zig
161+
pub const rpc_methods = struct {
162+
pub fn ping() []const u8 { return "pong"; }
163+
pub fn add(a: i64, b: i64) i64 { return a + b; }
164+
};
165+
```
166+
167+
Then you can:
168+
- Serve runtime-generated client script: `service.rpcClientScript(.{})`
169+
- Generate compile-time client script: `webui.Service.generatedClientScriptComptime(rpc_methods, .{})`
170+
- Generate compile-time TypeScript declarations: `webui.Service.generatedTypeScriptDeclarationsComptime(rpc_methods, .{})`
171+
172+
Script execution APIs:
173+
- `Window.runScript(script, options)`
174+
- `Window.evalScript(allocator, script, options)`
175+
176+
## Browser Support (Discovery Catalog)
177+
178+
The discovery catalog includes at least these families:
179+
- Firefox, Chrome, Edge, Chromium, Yandex, Brave, Vivaldi
180+
- Epic, Safari, Opera
181+
- Plus: Arc, DuckDuckGo, Tor, LibreWolf, Mullvad, Sidekick, Shift, Opera GX, Pale Moon, SigmaOS, Lightpanda
182+
183+
Notes:
184+
- Discovery means executable/path support in the catalog and search paths.
185+
- Actual availability still depends on what is installable on each OS.
186+
- Env overrides are supported: `WEBUI_BROWSER_PATH`, `WEBUI_BROWSER`, `BROWSER`.
187+
188+
## Runtime Helper JS Assets
189+
190+
Runtime helper JS is maintained as a source file and exposed in two variants:
191+
- `webui.runtime_helpers_js` (embedded variant)
192+
- `webui.runtime_helpers_js_written` (written-file variant)
193+
194+
Build outputs:
195+
- `zig-out/share/webui/runtime_helpers.embed.js`
196+
- `zig-out/share/webui/runtime_helpers.written.js`
197+
198+
## Examples
199+
200+
Available `-Dexample=` values:
201+
- `minimal`
202+
- `call_js_from_zig`
203+
- `call_zig_from_js`
204+
- `serve_folder`
205+
- `vfs`
206+
- `public_network`
207+
- `multi_client`
208+
- `chatgpt_api`
209+
- `custom_web_server`
210+
- `react`
211+
- `frameless`
212+
- `fancy_window`
213+
- `translucent_rounded`
214+
- `text_editor`
215+
- `minimal_oop`
216+
- `call_js_oop`
217+
- `call_oop_from_js`
218+
- `serve_folder_oop`
219+
- `vfs_oop`
220+
- `all` (default for `zig build run`)
221+
222+
## Production Notes
223+
224+
What is strong now:
225+
- Typed RPC and generated bridge tooling.
226+
- Browser discovery breadth and fallback policy controls.
227+
- Build/test/parity automation (`parity-local`, `os-matrix`, static guards).
228+
229+
What still needs completion for strict full parity:
230+
- TLS-enabled transport should be true HTTPS end-to-end (currently TLS state exists but transport path is still partial).
231+
- Visual parity for transparency/frameless/corner radius is still marked partial and relies on manual GUI validation.
232+
233+
Use `docs/manual_gui_checklist.md` for required Linux/macOS/Windows smoke validation.
234+
235+
## Repository Layout
236+
237+
- `src/` - active Zig runtime and API.
238+
- `tools/` - build-time generators (`bridge_gen.zig`, `vfs_gen.zig`, asset tooling).
239+
- `webui/examples/` - Zig example entrypoints and example assets.
240+
- `docs/` - parity and manual validation docs.
241+
- `parity/` - parity status + report definitions.
242+
243+
## Migration Docs
244+
245+
- `MIGRATION.md`
246+
- `CHANGELOG.md`
247+
- `docs/upstream_file_parity.md`

0 commit comments

Comments
 (0)