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), thenrender(data, allocator). Inside a handler,c.viewis the usual way. - spider.RawHtml: Trusted markup for templates:
{ expr }escapes everything else.
spider.Template
pub const Template = struct
A parsed template. init parses the source, render and renderFragment produce the HTML, deinit frees the parsed tree.
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 toinit;deinitfrees with it.components: ?std.StringHashMapUnmanaged([]const u8) = null: Component and layout sources by name. Set it afterinitto give the template the components it uses; the map then stays yours anddeinitdoes 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 anddeinitfrees it.inline_components: ?std.StringHashMapUnmanaged([]const u8) = null: The components the parser found defined inside the template, until the first render moves them intocomponents.layout: ?[]const u8 = null: The name given byextends "name"at the very start of the source, or null.renderlooks 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 whendeinitfreescomponents.base_components: ?*const embedded.Map = null: Read-only components shared by every render (Ctx.view() passes the embedded templates here). Looked up aftercomponents, 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() passescurrent_userhere). A name the data has too keeps the data's value. Not copied or freed here.
Template.Global
pub const Global = struct { name: []const u8, value: Value }
One entry of globals: a name and its value.
Template.init
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
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
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
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
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.
return c.view("page", .{ .body = spider.RawHtml{ .html = rendered } }, .{});