mirror of
https://github.com/jetzig-framework/jetzig.git
synced 2025-05-14 14:06:08 +00:00
Upgrade Zmpl (latest version provides partials), fix mime map memory leak
This commit is contained in:
parent
ce93abcd65
commit
29f4771264
@ -12,7 +12,6 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
const template_path = b.option([]const u8, "zmpl_templates_path", "Path to templates") orelse "src/app/views/";
|
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(.{
|
const lib = b.addStaticLibrary(.{
|
||||||
.name = "jetzig",
|
.name = "jetzig",
|
||||||
@ -35,7 +34,6 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.zmpl_templates_path = template_path,
|
.zmpl_templates_path = template_path,
|
||||||
.zmpl_manifest_path = manifest,
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
.version = "0.0.0",
|
.version = "0.0.0",
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.zmpl = .{
|
.zmpl = .{
|
||||||
.url = "https://github.com/jetzig-framework/zmpl/archive/84a712349e0cf679fc5c9900b805335d51d9ce86.tar.gz",
|
.url = "https://github.com/jetzig-framework/zmpl/archive/aa7147f8a52d927dce6cdd4f5b3bb2de5080f28c.tar.gz",
|
||||||
.hash = "1220e9f2133f6cd24c370850cbe3816e3d8b97c33dd822bf7eaf8f6f0ea2cfd2f8db",
|
.hash = "12203d262b39b2328adb981e41c5127507f3d47e977c1a4e69a96688a4213b986d04",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -55,13 +55,9 @@ pub fn build(b: *std.Build) !void {
|
|||||||
lib.root_module.addImport("routes", routes_module);
|
lib.root_module.addImport("routes", routes_module);
|
||||||
routes_module.addImport("jetzig", jetzig_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("routes", routes_module);
|
||||||
exe_static_routes.root_module.addImport("jetzig", jetzig_module);
|
exe_static_routes.root_module.addImport("jetzig", jetzig_module);
|
||||||
exe_static_routes.root_module.addImport("templates", templates_module);
|
exe_static_routes.root_module.addImport("zmpl", zmpl_module);
|
||||||
templates_module.addImport("zmpl", zmpl_module);
|
|
||||||
|
|
||||||
const run_static_routes_cmd = b.addRunArtifact(exe_static_routes);
|
const run_static_routes_cmd = b.addRunArtifact(exe_static_routes);
|
||||||
exe.step.dependOn(&run_static_routes_cmd.step);
|
exe.step.dependOn(&run_static_routes_cmd.step);
|
||||||
|
BIN
demo/public/favicon.ico
Normal file
BIN
demo/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
9
demo/src/app/views/root/_quotes.zmpl
Normal file
9
demo/src/app/views/root/_quotes.zmpl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<div>
|
||||||
|
<h1 class="text-3xl text-center p-3 pb-6 font-bold">{.message}</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button hx-get="/quotes/random" hx-trigger="click" hx-target="#quote" class="bg-[#39b54a] text-white font-bold py-2 px-4 rounded">Click Me</button>
|
||||||
|
|
||||||
|
<div id="quote" class="p-7 mx-auto w-1/2">
|
||||||
|
<div hx-get="/quotes/init" hx-trigger="load"></div>
|
||||||
|
</div>
|
@ -10,15 +10,8 @@
|
|||||||
<div class="text-center pt-10 m-auto">
|
<div class="text-center pt-10 m-auto">
|
||||||
<div><img class="p-3 mx-auto" src="/jetzig.png" /></div>
|
<div><img class="p-3 mx-auto" src="/jetzig.png" /></div>
|
||||||
|
|
||||||
<div>
|
// Renders `src/app/views/root/_quotes.zmpl`:
|
||||||
<h1 class="text-3xl text-center p-3 pb-6 font-bold">{.message}</h1>
|
<div>{^root/quotes}</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<button hx-get="/quotes/random" hx-trigger="click" hx-target="#quote" class="bg-[#39b54a] text-white font-bold py-2 px-4 rounded">Click Me</button>
|
|
||||||
|
|
||||||
<div id="quote" class="p-7 mx-auto w-1/2">
|
|
||||||
<div hx-get="/quotes/init" hx-trigger="load"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<a href="https://github.com/jetzig-framework/zmpl">
|
<a href="https://github.com/jetzig-framework/zmpl">
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const jetzig = @import("jetzig");
|
pub const jetzig = @import("jetzig");
|
||||||
pub const templates = @import("app/views/zmpl.manifest.zig").templates;
|
|
||||||
pub const routes = @import("routes").routes;
|
pub const routes = @import("routes").routes;
|
||||||
|
|
||||||
pub const jetzig_options = struct {
|
pub const jetzig_options = struct {
|
||||||
@ -16,8 +15,5 @@ pub fn main() !void {
|
|||||||
const app = try jetzig.init(allocator);
|
const app = try jetzig.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
try app.start(
|
try app.start(comptime jetzig.route(routes));
|
||||||
comptime jetzig.route(routes),
|
|
||||||
comptime jetzig.loadTemplates(templates),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
|
||||||
};
|
|
@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const jetzig = @import("jetzig");
|
const jetzig = @import("jetzig");
|
||||||
const routes = @import("routes").routes;
|
const routes = @import("routes").routes;
|
||||||
const templates = @import("templates").templates;
|
const zmpl = @import("zmpl");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
@ -94,8 +94,7 @@ fn writeContent(
|
|||||||
|
|
||||||
std.debug.print("[jetzig] Compiled static route: {s}\n", .{json_path});
|
std.debug.print("[jetzig] Compiled static route: {s}\n", .{json_path});
|
||||||
|
|
||||||
if (@hasDecl(templates, route.template)) {
|
if (zmpl.find(route.template)) |template| {
|
||||||
const template = @field(templates, route.template);
|
|
||||||
const html_path = try std.mem.concat(
|
const html_path = try std.mem.concat(
|
||||||
allocator,
|
allocator,
|
||||||
u8,
|
u8,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
pub const jetzig = @import("jetzig");
|
pub const jetzig = @import("jetzig");
|
||||||
pub const templates = @import("app/views/zmpl.manifest.zig").templates;
|
pub const routes = @import("routes").routes;
|
||||||
pub const routes = @import("app/views/routes.zig").routes;
|
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||||
@ -12,8 +11,5 @@ pub fn main() !void {
|
|||||||
const app = try jetzig.init(allocator);
|
const app = try jetzig.init(allocator);
|
||||||
defer app.deinit();
|
defer app.deinit();
|
||||||
|
|
||||||
try app.start(
|
try app.start(comptime jetzig.route(routes));
|
||||||
comptime jetzig.route(routes),
|
|
||||||
comptime jetzig.loadTemplates(templates),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -153,31 +153,6 @@ pub fn route(comptime routes: anytype) []views.Route {
|
|||||||
return &detected;
|
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 {
|
pub fn generateSecret(allocator: std.mem.Allocator) ![]const u8 {
|
||||||
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
var secret: [64]u8 = undefined;
|
var secret: [64]u8 = undefined;
|
||||||
|
@ -18,7 +18,7 @@ pub fn deinit(self: Self) void {
|
|||||||
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
/// Starts an application. `routes` should be `@import("routes").routes`, a generated file
|
||||||
/// automatically created at build time. `templates` should be
|
/// automatically created at build time. `templates` should be
|
||||||
/// `@import("src/app/views/zmpl.manifest.zig").templates`, created by Zmpl at compile time.
|
/// `@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);
|
var mime_map = jetzig.http.mime.MimeMap.init(self.allocator);
|
||||||
defer mime_map.deinit();
|
defer mime_map.deinit();
|
||||||
try mime_map.build();
|
try mime_map.build();
|
||||||
@ -54,7 +54,6 @@ pub fn start(self: Self, comptime_routes: []jetzig.views.Route, templates: []jet
|
|||||||
self.port,
|
self.port,
|
||||||
self.server_options,
|
self.server_options,
|
||||||
routes.items,
|
routes.items,
|
||||||
templates,
|
|
||||||
&mime_map,
|
&mime_map,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const jetzig = @import("../../jetzig.zig");
|
const jetzig = @import("../../jetzig.zig");
|
||||||
|
const zmpl = @import("zmpl");
|
||||||
|
|
||||||
const root_file = @import("root");
|
const root_file = @import("root");
|
||||||
|
|
||||||
@ -24,7 +25,6 @@ logger: jetzig.loggers.Logger,
|
|||||||
options: ServerOptions,
|
options: ServerOptions,
|
||||||
start_time: i128 = undefined,
|
start_time: i128 = undefined,
|
||||||
routes: []*jetzig.views.Route,
|
routes: []*jetzig.views.Route,
|
||||||
templates: []jetzig.TemplateFn,
|
|
||||||
mime_map: *jetzig.http.mime.MimeMap,
|
mime_map: *jetzig.http.mime.MimeMap,
|
||||||
std_net_server: std.net.Server = undefined,
|
std_net_server: std.net.Server = undefined,
|
||||||
|
|
||||||
@ -36,7 +36,6 @@ pub fn init(
|
|||||||
port: u16,
|
port: u16,
|
||||||
options: ServerOptions,
|
options: ServerOptions,
|
||||||
routes: []*jetzig.views.Route,
|
routes: []*jetzig.views.Route,
|
||||||
templates: []jetzig.TemplateFn,
|
|
||||||
mime_map: *jetzig.http.mime.MimeMap,
|
mime_map: *jetzig.http.mime.MimeMap,
|
||||||
) Self {
|
) Self {
|
||||||
return .{
|
return .{
|
||||||
@ -47,7 +46,6 @@ pub fn init(
|
|||||||
.logger = options.logger,
|
.logger = options.logger,
|
||||||
.options = options,
|
.options = options,
|
||||||
.routes = routes,
|
.routes = routes,
|
||||||
.templates = templates,
|
|
||||||
.mime_map = mime_map,
|
.mime_map = mime_map,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -123,7 +121,7 @@ fn renderResponse(self: *Self, request: *jetzig.http.Request) !void {
|
|||||||
const rendered = try self.renderInternalServerError(request, err);
|
const rendered = try self.renderInternalServerError(request, err);
|
||||||
|
|
||||||
request.response.content = rendered.content;
|
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";
|
request.response.content_type = "text/html";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -155,15 +153,19 @@ fn renderHTML(
|
|||||||
route: ?*jetzig.views.Route,
|
route: ?*jetzig.views.Route,
|
||||||
) !void {
|
) !void {
|
||||||
if (route) |matched_route| {
|
if (route) |matched_route| {
|
||||||
for (self.templates) |template| {
|
if (zmpl.find(matched_route.template)) |template| {
|
||||||
// TODO: Use a hashmap to avoid O(n)
|
const rendered = self.renderView(matched_route, request, template) catch |err| {
|
||||||
if (std.mem.eql(u8, matched_route.template, template.name)) {
|
if (isUnhandledError(err)) return err;
|
||||||
const rendered = try self.renderView(matched_route, request, template);
|
const rendered_error = try self.renderInternalServerError(request, err);
|
||||||
request.response.content = rendered.content;
|
request.response.content = rendered_error.content;
|
||||||
request.response.status_code = rendered.view.status_code;
|
request.response.status_code = rendered_error.view.status_code;
|
||||||
request.response.content_type = "text/html";
|
request.response.content_type = "text/html";
|
||||||
return;
|
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,
|
self: *Self,
|
||||||
route: *jetzig.views.Route,
|
route: *jetzig.views.Route,
|
||||||
request: *jetzig.http.Request,
|
request: *jetzig.http.Request,
|
||||||
template: ?jetzig.TemplateFn,
|
template: ?zmpl.manifest.Template,
|
||||||
) !RenderedView {
|
) !RenderedView {
|
||||||
const view = route.render(route.*, request) catch |err| {
|
const view = route.render(route.*, request) catch |err| {
|
||||||
self.logger.debug("Encountered error: {s}", .{@errorName(err)});
|
self.logger.debug("Encountered error: {s}", .{@errorName(err)});
|
||||||
|
@ -31,19 +31,14 @@ pub const MimeMap = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *MimeMap) void {
|
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();
|
self.map.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(self: *MimeMap) !void {
|
pub fn build(self: *MimeMap) !void {
|
||||||
for (mime_types) |mime_type| {
|
for (mime_types) |mime_type| {
|
||||||
try self.map.put(
|
try self.map.put(
|
||||||
try self.allocator.dupe(u8, mime_type.file_type),
|
mime_type.file_type,
|
||||||
try self.allocator.dupe(u8, mime_type.name),
|
mime_type.name,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user