follow PugJs

This commit is contained in:
2026-01-24 23:53:19 +05:30
parent 621f8def47
commit 27c4898706
893 changed files with 44597 additions and 10484 deletions

View File

@@ -14,13 +14,6 @@ pub fn build(b: *std.Build) void {
.optimize = optimize,
});
// Compile templates at build time using pugz's build_templates
// Generates views/generated.zig with all templates
const build_templates = @import("pugz").build_templates;
const compiled_templates = build_templates.compileTemplates(b, .{
.source_dir = "views",
});
// Main executable
const exe = b.addExecutable(.{
.name = "demo",
@@ -31,7 +24,6 @@ pub fn build(b: *std.Build) void {
.imports = &.{
.{ .name = "pugz", .module = pugz_dep.module("pugz") },
.{ .name = "httpz", .module = httpz_dep.module("httpz") },
.{ .name = "tpls", .module = compiled_templates },
},
}),
});

View File

@@ -1,22 +1,16 @@
//! Pugz Demo - Interpreted vs Compiled Templates
//! Pugz Demo - ViewEngine Template Rendering
//!
//! This demo shows two approaches:
//! 1. **Interpreted** (ViewEngine) - supports extends/blocks, parsed at runtime
//! 2. **Compiled** (build-time) - 3x faster, templates compiled to Zig code
//! This demo shows how to use ViewEngine for server-side rendering.
//!
//! Routes:
//! GET / - Compiled home page (fast)
//! GET /users - Compiled users list (fast)
//! GET /interpreted - Interpreted with inheritance (flexible)
//! GET /page-a - Interpreted page A
//! GET / - Home page
//! GET /users - Users list
//! GET /page-a - Page with data
const std = @import("std");
const httpz = @import("httpz");
const pugz = @import("pugz");
// Compiled templates - generated at build time from views/compiled/*.pug
const tpls = @import("tpls");
const Allocator = std.mem.Allocator;
/// Application state shared across all requests
@@ -42,33 +36,28 @@ pub fn main() !void {
var app = App.init(allocator);
const port = 8080;
const port = 8081;
var server = try httpz.Server(*App).init(allocator, .{ .port = port }, &app);
defer server.deinit();
var router = try server.router(.{});
// Compiled template routes (fast - 3x faster than Pug.js)
router.get("/", indexCompiled, .{});
router.get("/users", usersCompiled, .{});
// Interpreted template routes (flexible - supports extends/blocks)
router.get("/interpreted", indexInterpreted, .{});
router.get("/", index, .{});
router.get("/users", users, .{});
router.get("/page-a", pageA, .{});
router.get("/mixin-test", mixinTest, .{});
std.debug.print(
\\
\\Pugz Demo - Interpreted vs Compiled Templates
\\=============================================
\\Pugz Demo - ViewEngine Template Rendering
\\==========================================
\\Server running at http://localhost:{d}
\\
\\Compiled routes (3x faster than Pug.js):
\\ GET / - Home page (compiled)
\\ GET /users - Users list (compiled)
\\
\\Interpreted routes (supports extends/blocks):
\\ GET /interpreted - Home with ViewEngine
\\ GET /page-a - Page with inheritance
\\Routes:
\\ GET / - Home page
\\ GET /users - Users list
\\ GET /page-a - Page with data
\\ GET /mixin-test - Mixin test page
\\
\\Press Ctrl+C to stop.
\\
@@ -77,57 +66,10 @@ pub fn main() !void {
try server.listen();
}
// ─────────────────────────────────────────────────────────────────────────────
// Compiled template handlers (fast - no parsing at runtime)
// ─────────────────────────────────────────────────────────────────────────────
/// GET / - Compiled home page
fn indexCompiled(_: *App, _: *httpz.Request, res: *httpz.Response) !void {
const html = tpls.home(res.arena, .{
.title = "Welcome - Compiled",
.authenticated = true,
}) catch |err| {
res.status = 500;
res.body = @errorName(err);
return;
};
res.content_type = .HTML;
res.body = html;
}
/// GET /users - Compiled users list
fn usersCompiled(_: *App, _: *httpz.Request, res: *httpz.Response) !void {
const User = struct {
name: []const u8,
email: []const u8,
};
const html = tpls.users(res.arena, .{
.title = "Users - Compiled",
.users = &[_]User{
.{ .name = "Alice", .email = "alice@example.com" },
.{ .name = "Bob", .email = "bob@example.com" },
.{ .name = "Charlie", .email = "charlie@example.com" },
},
}) catch |err| {
res.status = 500;
res.body = @errorName(err);
return;
};
res.content_type = .HTML;
res.body = html;
}
// ─────────────────────────────────────────────────────────────────────────────
// Interpreted template handlers (flexible - supports inheritance)
// ─────────────────────────────────────────────────────────────────────────────
/// GET /interpreted - Uses ViewEngine (parsed at runtime)
fn indexInterpreted(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
/// GET / - Home page
fn index(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
const html = app.view.render(res.arena, "index", .{
.title = "Home - Interpreted",
.title = "Welcome",
.authenticated = true,
}) catch |err| {
res.status = 500;
@@ -139,7 +81,21 @@ fn indexInterpreted(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
res.body = html;
}
/// GET /page-a - Demonstrates extends and block override
/// GET /users - Users list
fn users(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
const html = app.view.render(res.arena, "users", .{
.title = "Users",
}) catch |err| {
res.status = 500;
res.body = @errorName(err);
return;
};
res.content_type = .HTML;
res.body = html;
}
/// GET /page-a - Page with data
fn pageA(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
const html = app.view.render(res.arena, "page-a", .{
.title = "Page A - Pets",
@@ -154,3 +110,15 @@ fn pageA(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
res.content_type = .HTML;
res.body = html;
}
/// GET /mixin-test - Mixin test page
fn mixinTest(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
const html = app.view.render(res.arena, "mixin-test", .{}) catch |err| {
res.status = 500;
res.body = @errorName(err);
return;
};
res.content_type = .HTML;
res.body = html;
}

View File

@@ -214,6 +214,50 @@ pub fn page_a(a: Allocator, d: anytype) Allocator.Error![]u8 {
return o.items;
}
pub fn mixin_test(a: Allocator, d: anytype) Allocator.Error![]u8 {
var o: ArrayList = .empty;
try o.appendSlice(a, "<!DOCTYPE html><html><head><title>Mixin Test</title></head><body><h1>Mixin Test Page</h1><p>Testing button mixin:</p>");
{
const text = "Click Me";
const @"type" = "primary";
try o.appendSlice(a, "<button");
try o.appendSlice(a, " class=\"");
try o.appendSlice(a, "btn btn-");
try o.appendSlice(a, strVal(@"type"));
try o.appendSlice(a, "\"");
try o.appendSlice(a, ">");
try esc(&o, a, strVal(text));
try o.appendSlice(a, "</button>");
}
{
const text = "Cancel";
const @"type" = "btn btn-secondary";
try o.appendSlice(a, "<button");
try o.appendSlice(a, " class=\"");
try o.appendSlice(a, "btn btn-");
try o.appendSlice(a, strVal(@"type"));
try o.appendSlice(a, "\"");
try o.appendSlice(a, ">");
try esc(&o, a, strVal(text));
try o.appendSlice(a, "</button>");
}
try o.appendSlice(a, "<p>Testing link mixin:</p>");
{
const href = "/home";
const text = "Go Home";
try o.appendSlice(a, "<a class=\"btn btn-link\"");
try o.appendSlice(a, " href=\"");
try o.appendSlice(a, strVal(href));
try o.appendSlice(a, "\"");
try o.appendSlice(a, ">");
try esc(&o, a, strVal(text));
try o.appendSlice(a, "</a>");
}
try o.appendSlice(a, "</body></html>");
_ = d;
return o.items;
}
pub fn page_b(a: Allocator, d: anytype) Allocator.Error![]u8 {
var o: ArrayList = .empty;
try o.appendSlice(a, "<html><head><title>My Site - ");
@@ -281,6 +325,7 @@ pub const template_names = [_][]const u8{
"mixins_input_text",
"home",
"page_a",
"mixin_test",
"page_b",
"layout_2",
"layout",

View File

@@ -0,0 +1,15 @@
include mixins/buttons.pug
doctype html
html
head
title Mixin Test
body
h1 Mixin Test Page
p Testing button mixin:
+btn("Click Me")
+btn("Cancel", "secondary")
p Testing link mixin:
+btn-link("/home", "Go Home")