Zig Electron Replacement

Watched Andrew’s video about data oriented design the other day and it got me thinking about what apps unnecessarily slow me down on a daily basis. The road always came back to electron. Since zig already has bun, would there be any interest in a z based drop in electron replacement. We can call it zelectron until a less shitty name is proposed.

3 Likes

How would you approach the ‘browser engine problem’?

You could use the operating system webview like Tauri, Cordova or GitHub - webview/webview: Tiny cross-platform webview library for C/C++. Uses WebKit (GTK/Cocoa) and Edge WebView2 (Windows). (formerly known as zserge/webview), that would allow small application bundles but at the cost that you’ll need to worry about non-Chromium browser engines.

…or the alternative would be integrating Chromium, but then that wouldn’t be much of an advantage over using Electron in the first place.

But in both cases you wouldn’t see any performance advantage over Electron, because in the end all code that needs to do any rendering needs to go through JS-APIs, you could at most delegate the ‘application logic’ into a FFI-DLL compiled from Zig code (but then you can already do that with Electron or Tauri).

Getting rid of the browser engine completely would mean that it’s more like a native cross-platform application framework like Qt or GTK, but then it wouldn’t need a V8^H^HJavaScriptCore wrapper like Bun, nor would it be anything like Electron.

4 Likes

Zig bindings for WebUI might be an adequate starting point, and may already exist.

I will say that native GUI bindings will always feel and function nicer than what WebView can provide, but there’s a place for them nonetheless. Zig’s native cross-compilation and WASM targeting are strengths here.

I would much rather deal with the quirks of Safari (let’s face it, it’s Chrome or it’s Safari at this point) than inflict an entire bundled web browser on users. It feels like an insult to the spirit of Zig to use it to ship a multi-gigabyte binary which loads into a minimum GB of memory.

Making pure-Zig cross-platform native GUI in the style of QT, well it’s a very different story. Promising, actually, but what I’m gesturing at is that your post (@floooh) explores three very different projects.

Two of which are quite promising, and one of those is immensely easier than the other, although even “what if Tauri but Zig” is only ‘easy’ by comparison with writing a modern QT equivalent from scratch.

Good idea though? Yes.

1 Like

Electron is kinda a pain due to the separation between the renderer thread and the background thread. Something that works like NW.js where the two are unified would be a major improvement.

Have you taken a look at Orca? It’s not written in Zig, but it is a cross platform alternative that provides a lot of the benefits of electron with none of the browser jank.

@kristoff did an interview with the head developer on Zig Showtime. It’s a good watch.

2 Likes

This project popped up in my Github feed yesterday:

1 Like

That is sweet. Thank you for sharing; this will be fun to dig into.

To be candid, I got spooked away from the general solution after appreciating how much work a new rendering engine would be, and how futile it would ultimately be if we turned around and chose to use chromium under the hood ourselves. It seemed like making not chrome based messaging/conferencing apps directly to compete with Slack/Zoom straight on would be easier than solving all of electron.

5 Likes

I had an idea. What if it really could be done so that html and css are processed at compile-time into GUI objects with styles and descriptors for transitions etc. It’s like writing a compiler for html/css… Unreal… Almost.

P.S. Imagine writing it in C-macros… ugh…

1 Like

I actually went down this route two months ago. I got good results, but I decided an HTML-driven UI wouldn’t be enough for my use case.

My approach was to emulate Vue.js. You write an HTML template file with a corresponding zig file, e.g. MyApp.html, MyApp.zig. The HTML file is parsed and converted into a struct which has, among other things, a data field which is the struct of the zig file. Basically, using all the meta data available at comp time, you don’t actually have to parse the zig file get any info. The generated codes has a lot of @typeInfo calls.

In addition, a JS file is generated. It is responsible for manipulating the DOM (creating the elements, updating the dynamic attributes / text). The idea is to avoid having to cross the zig<->browser boundary with a bunch of low-level calls, e.g. createElement, setAttributes, appendChild, etc.

In my experiment, all the code is generated. There are no runtime notions of abstract “components” or “views” that exist as objects in memory with recursive iteration. In theory, that means that simple components will be inlined to more complex ones. The trade-off, of course, is a large amount of code is generated.

Performance-wise, it seemed pretty solid. I didn’t bother implementing any state management logic. Instead, I “re-rendered” after events. That just invoked dispatching specific events to the JS. It certainly wouldn’t work for very complex UIs, but was fine for simple stuff.

On the runtime-side, the zig code could be compiled to WASM in order to run inside a regular browser. I also wrote a basic WKWebView runtime for macOS. This allows all the zig code to run natively and the browser interaction is done via the WKWebView evaluateJavaScript and addScriptMessageHandler methods.

As mentioned, for my use case I really need full access to the GPU in native. Putting the webview on top of an OpenGL context. It was doable, but you have some layering issues. A basic example is trying to clip the context to some arbitrary elements in the web view. Not really doable with the public APIs.

So I decided to abandon that attempt.

The new approach I’m working on is to recreate a basic web-style interface engine. It’s more similar to React Native. Each platform uses the built-in libraries and, while it introduces a bit more work in that regard, it helps to have a smooth “native” feel as you can use the “official” APIs directly for input handling, rendering text, etc. On macOS, that is Cocoa/AppKit. On Windows, GDI/DirectWrite/Direct2D/whatever-else. For web, that is the DOM + CSS.

The interface is defined by zig code in the style of JSX. Obviously, certain aspects have to be different given the language differences between zig & JS.

We’ll see how this goes, but my current results are hopeful. My application is a CAD program and so most of my complicated logic takes place “inside” the canvas and so the UI elements are relative simple.

2 Likes