Adapting a spec after a prototype.
About
Now that I've written and implemented simple prototype for this framework, I wanted to make some adjustments based off how it went. I really liked this, and have high hopes for the project, a few things stuck out though, especially with how clunky this currently is.
Fix some wording
Calling the entry function 'page' is one of those things that felt a bit clunky, I am going to rename this to onLoad. This will be to enforce the similarity between client and generation time in the framework. I also want to rename elements to Units, the reasoning for this will be more obvious later, but in short I want to abstract this system completly away from html, js, and css.
I will also be moving the addChildren array to be a comptime tuple similar to the std.fmt.Format api, so I can throw things like strings into here and have it work like .text(). And also allow expanding without needing the union.
I will also be moving the addChildren array to be a comptime tuple similar to the std.fmt.Format api, so I can throw things like strings into here and have it work like .text(). And also allow expanding without needing the union.
The elephant in the room
Now that all the simple things have been brought up, there was a pretty big problem with the current spec. Right now when you use a generator in your page function the wasm backend will not emit the function. This is due to zigs lazy eval. I will need some way to indicate depenedent generators, the plan is to remake generator to be completly comptime.
I also noticed that this framework can be expanded past generation and clients. This in mind, I will expand the spec a bit to allow for that.
I also noticed that this framework can be expanded past generation and clients. This in mind, I will expand the spec a bit to allow for that.
A new template
All these changes will look something like this:
const web = @import("web_framework");
pub const main = web.mainFn(@This());
const Index = @This();
const Example = struct {
text: []const u8,
server: *Unit,
pub fn onLoad(root: *web.Unit, self: Example) !void {
const serverText = self.server.call("getHello", .{});
try root.addChildren(.{
web.Tag("p", .{self.text}),
web.Tag("p", .{"server says: ", serverText}),
});
}
};
const Server = struct {
pub fn getHello(_: *web.Unit, _: Server) []const u8 {
return "Hello World!";
}
// onload should not be required
};
pub fn onLoad(root: *web.Unit, _: Index) !void {
// Since servers are a unit, you can @import it and keep the code seperate.
const server = web.Script(.server, Server)(.{});
try root.addChildren(.{
web.Tag("h1", .{"Example of the new api"}),
web.Script(.client, Example)(.{
.text = "Example Template",
.server = server,
}),
server,
// templates if it wasnt obvious from the previous post, can be made with @import
web.Script(.generated, @import("footer.zig"))(.{}),
});
}
Tune in next time for some amazing style sheets 😉.
Links
Last Modified 2026 05/11