Zig 0.17.0

Template and RawHtml

On this page:

  • spider.Template: A template parsed from text, for rendering outside a request (an email body, a file): Template.init(allocator, text), then render(data, allocator). Inside a handler, c.view is the usual way.
  • spider.RawHtml: Trusted markup for templates: { expr } escapes everything else.

spider.Template

zig
pub const Template = struct

A parsed template. init parses the source, render and renderFragment produce the HTML, deinit frees the parsed tree.

zig
var tmpl = try spider.Template.init(alc, "Hello { name }!");
defer tmpl.deinit();
const html = try tmpl.render(.{ .name = "World" }, alc);
defer alc.free(html);

{ expr } is HTML-escaped, except a spider.RawHtml value.

Fields

  • nodes: []Node: The parsed template, owned by the template. Read-only for apps.
  • allocator: std.mem.Allocator: The allocator given to init; deinit frees with it.
  • components: ?std.StringHashMapUnmanaged([]const u8) = null: Component and layout sources by name. Set it after init to give the template the components it uses; the map then stays yours and deinit does not free it (the first render adds the template's inline components to it, allocated with that render's allocator). Left null, the first render creates it from the components defined inline in the template and deinit frees it.
  • inline_components: ?std.StringHashMapUnmanaged([]const u8) = null: The components the parser found defined inside the template, until the first render moves them into components.
  • layout: ?[]const u8 = null: The name given by extends "name" at the very start of the source, or null. render looks it up among the components.
  • is_root: bool = false: True when the source contains <html. Nothing in Spider reads it.
  • owns_components: bool = false: Read-only: true when deinit frees components.
  • base_components: ?*const embedded.Map = null: Read-only components shared by every render (Ctx.view() passes the embedded templates here). Looked up after components, so inline components still take precedence; never modified or freed.
  • globals: []const Global = &.{}: Names every render of this template can use besides its data (Ctx.view() passes current_user here). A name the data has too keeps the data's value. Not copied or freed here.

Template.Global

zig
pub const Global = struct { name: []const u8, value: Value }

One entry of globals: a name and its value.

Template.init

zig
pub fn init(alc: std.mem.Allocator, template_str: []const u8) !Template

Parses template_str. The parsed tree is allocated with alc and holds copies: the source can be freed after this returns. Fails with the parser's error on a malformed template (error.UnclosedInterpolation, error.UnclosedBrace, error.UnclosedParen, error.ExpectedBrace, error.ExpectedCapture, error.UnclosedCapture) or error.OutOfMemory.

Template.deinit

zig
pub fn deinit(self: *Template) void

Frees the parsed tree, and components when the template created the map itself. Strings returned by render are not freed here.

Template.render

zig
pub fn render(self: *Template, context: anytype, alc: std.mem.Allocator) ![]const u8

Renders the template with context, a struct whose fields are the names the template reads (.{} for none). Returns the HTML, allocated with alc and owned by the caller.

With extends "name", the result is that layout with this template in its slot. A layout that is not among the components is not an error: the template renders alone, and a warning in the log names the layout.

Fails with error.ComponentDepthExceeded when components nest deeper than spider.template_max_component_depth, with a parser error from a malformed component or layout, or error.OutOfMemory.

Template.renderFragment

zig
pub fn renderFragment(self: *Template, component_name: []const u8, context: anytype, alc: std.mem.Allocator) ![]const u8

Renders only a single named component (inline or file) from this template, skipping layout and root-level nodes entirely. context is the data, as in render. The HTML is allocated with alc and owned by the caller. Returns error.ComponentNotFound if the component name is not registered; otherwise fails like render.

spider.RawHtml

zig
pub const RawHtml = struct { html: []const u8 }

Trusted HTML for a template: { expr } escapes every string except a RawHtml, which is emitted verbatim. Wrap only markup your code built itself (or already escaped), never user input.

zig
return c.view("page", .{ .body = spider.RawHtml{ .html = rendered } }, .{});