I think in general, you may want to compile to WASM, I personally, wouldn’t see a purpose in using a framework, that I can’t write zig in, but transpiles to zig, which then transpiles to html. It would seem like a lot of extra steps just to get to a point where I am writing React or Svelte. If you really want to have the performance benefits of Zig, maybe compile a wasm binary, and build a JS bridge, the overhead of going from WASM to JS, is negligible at this point. At the end of the day, everything is just html, and React, Svelte, whatever, just generate html, the questions is where the performance exists.
A big reason state management exists, is due to Javascripts lack of performance, you could try building a mini immediate mode gui, where the entire UI tree is reconciled and rendered on each pass. This is what CLAY: GitHub - nicbarker/clay: High performance UI layout library in C. has done.
Also in my humble opinion, perhaps consider what you want out of this framework. Zine Zine: A Static Site Generator Written in Zig | Loris Cro's Blog already does great SSG.
-
Are you looking to just learn, or do you want to build a full production grade framework?
-
Is the idea to use React for basic client side rendering, and then make use of WASM generated from Zig for performance? Or do you want WASM and Zig to handle the whole stack?
-
Most importantly what problem are you trying to solve? For example Golang Templ: GitHub - a-h/templ: A language for writing HTML user interfaces in Go., is a template engine for ssr in golang, which seems similar to your project?
I don’t want to be discouraging, but I also don’t want Zig, to become another Javascript ecosystem, where there are 1000 of frameworks, libraries, all doing something slightly different.
Overall, I think the project is a really cool idea, but it also seems like it doesn’t really know what it wants to be?
You can also look into Zig itself as a way to define your UI, for example you can return functions, that capture there children through a void argument like so:
////////////// Here is an example where Zig itself is the UI, and then you could use Zig itself to create UIs
Node.style(&.{
.size = .{ .width = .percent(50), .height = .percent(100) }, // 500
})({
Node.style(&.{
.size = .{ .width = .fit, .height = .percent(100) }, // 500
})({
Node.style(&.{
.size = .{ .width = .px(500), .height = .percent(100) },
})({});
});
Node.style(&.{
.size = .{ .width = .grow, .height = .percent(100) }, // 0
})({});
});
///////////////////////////////////////////////////////////////////////////
const Scram = @import("Scram.zig");
const Style = @import("Style.zig").Style;
const Node = Scram.Node;
/// The LifeCycle struct
/// allows control over ui node in the tree
/// exposes open, configure, and close, must be called in this order to attach the node to the tree
pub const LifeCycle = struct {
/// open takes an element decl and return a *UINode
/// this opens the element to allow for children
/// within the dom tree, node this current opened node is the current top stack node, ie any children
/// will reference this node as their parent
pub fn open() ?*Node {
const ui_node = Scram.instance.open() catch {
return null;
};
return ui_node;
}
/// close, closes the current UINode
pub fn close(_: void) void {
_ = Scram.instance.close();
return;
}
/// configure is used internally to configure the UINode, used for adding text props, or hover props ect
/// within configure, we check if the node has a id if so we use that, otherwise later we generate one
/// we also set various props, such as text, style, is an SVG or not
/// Any mainpulation of the node after this point is considered undefined behaviour be cautious;
pub fn configure(style_ptr: ?*const Style) void {
_ = Scram.instance.configure(style_ptr);
}
};
const Self = @This();
pub inline fn style(_: *const Self, style_ptr: *const Style) fn (void) void {
_ = LifeCycle.open() orelse unreachable;
LifeCycle.configure(style_ptr);
return LifeCycle.close;
}