diff --git a/build.zig b/build.zig index b714831..0902c8f 100644 --- a/build.zig +++ b/build.zig @@ -12,7 +12,6 @@ pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const template_path = b.option([]const u8, "zmpl_templates_path", "Path to templates") orelse "src/app/views/"; - const manifest: []const u8 = b.pathJoin(&.{ template_path, "zmpl.manifest.zig" }); const lib = b.addStaticLibrary(.{ .name = "jetzig", @@ -35,7 +34,6 @@ pub fn build(b: *std.Build) !void { .target = target, .optimize = optimize, .zmpl_templates_path = template_path, - .zmpl_manifest_path = manifest, }, ); diff --git a/build.zig.zon b/build.zig.zon index 440427b..6a6f26e 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -3,8 +3,8 @@ .version = "0.0.0", .dependencies = .{ .zmpl = .{ - .url = "https://github.com/jetzig-framework/zmpl/archive/84a712349e0cf679fc5c9900b805335d51d9ce86.tar.gz", - .hash = "1220e9f2133f6cd24c370850cbe3816e3d8b97c33dd822bf7eaf8f6f0ea2cfd2f8db", + .url = "https://github.com/jetzig-framework/zmpl/archive/aa7147f8a52d927dce6cdd4f5b3bb2de5080f28c.tar.gz", + .hash = "12203d262b39b2328adb981e41c5127507f3d47e977c1a4e69a96688a4213b986d04", }, }, diff --git a/demo/build.zig b/demo/build.zig index c0d560f..834f4ff 100644 --- a/demo/build.zig +++ b/demo/build.zig @@ -55,13 +55,9 @@ pub fn build(b: *std.Build) !void { lib.root_module.addImport("routes", routes_module); routes_module.addImport("jetzig", jetzig_module); - const templates_module = b.createModule( - .{ .root_source_file = .{ .path = "src/app/views/zmpl.manifest.zig" } }, - ); exe_static_routes.root_module.addImport("routes", routes_module); exe_static_routes.root_module.addImport("jetzig", jetzig_module); - exe_static_routes.root_module.addImport("templates", templates_module); - templates_module.addImport("zmpl", zmpl_module); + exe_static_routes.root_module.addImport("zmpl", zmpl_module); const run_static_routes_cmd = b.addRunArtifact(exe_static_routes); exe.step.dependOn(&run_static_routes_cmd.step); diff --git a/demo/public/favicon.ico b/demo/public/favicon.ico new file mode 100644 index 0000000..0ccc92b Binary files /dev/null and b/demo/public/favicon.ico differ diff --git a/demo/src/app/views/root/_quotes.zmpl b/demo/src/app/views/root/_quotes.zmpl new file mode 100644 index 0000000..ef479e8 --- /dev/null +++ b/demo/src/app/views/root/_quotes.zmpl @@ -0,0 +1,9 @@ +
+

{.message}

+
+ + + +
+
+
diff --git a/demo/src/app/views/root/index.zmpl b/demo/src/app/views/root/index.zmpl index 57ee5cc..5de793a 100644 --- a/demo/src/app/views/root/index.zmpl +++ b/demo/src/app/views/root/index.zmpl @@ -10,15 +10,8 @@
-
-

{.message}

-
- - - -
-
-
+ // Renders `src/app/views/root/_quotes.zmpl`: +
{^root/quotes}
diff --git a/demo/src/main.zig b/demo/src/main.zig index d5fcd2b..8159618 100644 --- a/demo/src/main.zig +++ b/demo/src/main.zig @@ -1,7 +1,6 @@ const std = @import("std"); pub const jetzig = @import("jetzig"); -pub const templates = @import("app/views/zmpl.manifest.zig").templates; pub const routes = @import("routes").routes; pub const jetzig_options = struct { @@ -16,8 +15,5 @@ pub fn main() !void { const app = try jetzig.init(allocator); defer app.deinit(); - try app.start( - comptime jetzig.route(routes), - comptime jetzig.loadTemplates(templates), - ); + try app.start(comptime jetzig.route(routes)); } diff --git a/src/app/views/zmpl.manifest.zig b/src/app/views/zmpl.manifest.zig deleted file mode 100644 index 3d67249..0000000 --- a/src/app/views/zmpl.manifest.zig +++ /dev/null @@ -1,5 +0,0 @@ -// Zmpl template manifest. -// This file is automatically generated at build time. Manual edits will be discarded. -// This file should _not_ be stored in version control. -pub const templates = struct { -}; diff --git a/src/compile_static_routes.zig b/src/compile_static_routes.zig index cf03fca..149306e 100644 --- a/src/compile_static_routes.zig +++ b/src/compile_static_routes.zig @@ -1,7 +1,7 @@ const std = @import("std"); const jetzig = @import("jetzig"); const routes = @import("routes").routes; -const templates = @import("templates").templates; +const zmpl = @import("zmpl"); pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -94,8 +94,7 @@ fn writeContent( std.debug.print("[jetzig] Compiled static route: {s}\n", .{json_path}); - if (@hasDecl(templates, route.template)) { - const template = @field(templates, route.template); + if (zmpl.find(route.template)) |template| { const html_path = try std.mem.concat( allocator, u8, diff --git a/src/init/src/main.zig b/src/init/src/main.zig index 72b2899..a434403 100644 --- a/src/init/src/main.zig +++ b/src/init/src/main.zig @@ -1,8 +1,7 @@ const std = @import("std"); pub const jetzig = @import("jetzig"); -pub const templates = @import("app/views/zmpl.manifest.zig").templates; -pub const routes = @import("app/views/routes.zig").routes; +pub const routes = @import("routes").routes; pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; @@ -12,8 +11,5 @@ pub fn main() !void { const app = try jetzig.init(allocator); defer app.deinit(); - try app.start( - comptime jetzig.route(routes), - comptime jetzig.loadTemplates(templates), - ); + try app.start(comptime jetzig.route(routes)); } diff --git a/src/jetzig.zig b/src/jetzig.zig index 48d8b94..22945eb 100644 --- a/src/jetzig.zig +++ b/src/jetzig.zig @@ -153,31 +153,6 @@ pub fn route(comptime routes: anytype) []views.Route { return &detected; } -// Receives a type (an imported module). All pub const declarations are considered as compiled -// Zmpl templates, each implementing a `render` function. -pub fn loadTemplates(comptime module: type) []TemplateFn { - var size: u16 = 0; - const decls = @typeInfo(module).Struct.decls; - - for (decls) |_| size += 1; - - var detected: [size]TemplateFn = undefined; - - for (decls, 0..) |decl, decl_index| { - detected[decl_index] = .{ - .render = @field(module, decl.name).render, - .name = decl.name, - }; - } - - return &detected; -} - -pub const TemplateFn = struct { - name: []const u8, - render: *const fn (*zmpl.Data) anyerror![]const u8, -}; - pub fn generateSecret(allocator: std.mem.Allocator) ![]const u8 { const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; var secret: [64]u8 = undefined; diff --git a/src/jetzig/App.zig b/src/jetzig/App.zig index 8c2c645..96d3d15 100644 --- a/src/jetzig/App.zig +++ b/src/jetzig/App.zig @@ -18,7 +18,7 @@ pub fn deinit(self: Self) void { /// Starts an application. `routes` should be `@import("routes").routes`, a generated file /// automatically created at build time. `templates` should be /// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time. -pub fn start(self: Self, comptime_routes: []jetzig.views.Route, templates: []jetzig.TemplateFn) !void { +pub fn start(self: Self, comptime_routes: []jetzig.views.Route) !void { var mime_map = jetzig.http.mime.MimeMap.init(self.allocator); defer mime_map.deinit(); try mime_map.build(); @@ -54,7 +54,6 @@ pub fn start(self: Self, comptime_routes: []jetzig.views.Route, templates: []jet self.port, self.server_options, routes.items, - templates, &mime_map, ); diff --git a/src/jetzig/http/Server.zig b/src/jetzig/http/Server.zig index 098a87d..feb0d39 100644 --- a/src/jetzig/http/Server.zig +++ b/src/jetzig/http/Server.zig @@ -1,6 +1,7 @@ const std = @import("std"); const jetzig = @import("../../jetzig.zig"); +const zmpl = @import("zmpl"); const root_file = @import("root"); @@ -24,7 +25,6 @@ logger: jetzig.loggers.Logger, options: ServerOptions, start_time: i128 = undefined, routes: []*jetzig.views.Route, -templates: []jetzig.TemplateFn, mime_map: *jetzig.http.mime.MimeMap, std_net_server: std.net.Server = undefined, @@ -36,7 +36,6 @@ pub fn init( port: u16, options: ServerOptions, routes: []*jetzig.views.Route, - templates: []jetzig.TemplateFn, mime_map: *jetzig.http.mime.MimeMap, ) Self { return .{ @@ -47,7 +46,6 @@ pub fn init( .logger = options.logger, .options = options, .routes = routes, - .templates = templates, .mime_map = mime_map, }; } @@ -123,7 +121,7 @@ fn renderResponse(self: *Self, request: *jetzig.http.Request) !void { const rendered = try self.renderInternalServerError(request, err); request.response.content = rendered.content; - request.response.status_code = .internal_server_error; + request.response.status_code = rendered.view.status_code; request.response.content_type = "text/html"; return; @@ -155,15 +153,19 @@ fn renderHTML( route: ?*jetzig.views.Route, ) !void { if (route) |matched_route| { - for (self.templates) |template| { - // TODO: Use a hashmap to avoid O(n) - if (std.mem.eql(u8, matched_route.template, template.name)) { - const rendered = try self.renderView(matched_route, request, template); - request.response.content = rendered.content; - request.response.status_code = rendered.view.status_code; + if (zmpl.find(matched_route.template)) |template| { + const rendered = self.renderView(matched_route, request, template) catch |err| { + if (isUnhandledError(err)) return err; + const rendered_error = try self.renderInternalServerError(request, err); + request.response.content = rendered_error.content; + request.response.status_code = rendered_error.view.status_code; request.response.content_type = "text/html"; return; - } + }; + request.response.content = rendered.content; + request.response.status_code = rendered.view.status_code; + request.response.content_type = "text/html"; + return; } } @@ -200,7 +202,7 @@ fn renderView( self: *Self, route: *jetzig.views.Route, request: *jetzig.http.Request, - template: ?jetzig.TemplateFn, + template: ?zmpl.manifest.Template, ) !RenderedView { const view = route.render(route.*, request) catch |err| { self.logger.debug("Encountered error: {s}", .{@errorName(err)}); diff --git a/src/jetzig/http/mime.zig b/src/jetzig/http/mime.zig index 10b8732..7ccac2d 100644 --- a/src/jetzig/http/mime.zig +++ b/src/jetzig/http/mime.zig @@ -31,19 +31,14 @@ pub const MimeMap = struct { } pub fn deinit(self: *MimeMap) void { - var it = self.map.iterator(); - while (it.next()) |item| { - self.allocator.free(item.key_ptr.*); - self.allocator.free(item.value_ptr.*); - } self.map.deinit(); } pub fn build(self: *MimeMap) !void { for (mime_types) |mime_type| { try self.map.put( - try self.allocator.dupe(u8, mime_type.file_type), - try self.allocator.dupe(u8, mime_type.name), + mime_type.file_type, + mime_type.name, ); } }