Template Engine#
Built-in Handlebars-like template engine with zero dependencies. Perfect for email templates, HTML generation, and more.
Quick Start#
typescript
import { render } from "@buntok/core/template";
const html = render("Hello {{ name }}!", { name: "World" });
// → "Hello World!"Variables#
Use {{ variable }} to interpolate values. Supports dot notation for nested objects.
typescript
render("Hello {{ name }}!", { name: "Budi" });
// → "Hello Budi!"
render("{{ user.email }}", { user: { email: "budi@example.com" } });
// → "budi@example.com"Info
Variables are HTML-escaped by default. Use
{{{ rawHtml }}} for unescaped output.Raw HTML (Triple Braces)#
typescript
const html = "<b>Bold text</b>";
render("{{{ html }}}", { html });
// → "<b>Bold text</b>" (not escaped)Conditionals#
typescript
// Basic if
render("{{#if active}}Active{{/if}}", { active: true });
// → "Active"
// If/else
render("{{#if active}}Yes{{else}}No{{/if}}", { active: false });
// → "No"
// Unless (negative if)
render("{{#unless verified}}Please verify{{/unless}}", { verified: false });
// → "Please verify"Loops#
typescript
const items = [{ name: "A" }, { name: "B" }, { name: "C" }];
render("{{#each items}}{{name}} {{/each}}", { items });
// → "A B C "Info
Special variables in loops:
@index (0-based), @first (boolean), @last (boolean)typescript
render("{{#each items}}{{@index}}: {{name}}{{/each}}", {
items: [{ name: "X" }, { name: "Y" }],
});
// → "0: X1: Y"
render("{{#each items}}{{#if @first}}FIRST{{/if}} {{/each}}", {
items: ["a", "b", "c"],
});
// → "FIRST "Partials#
Reusable template fragments. Register once, use anywhere.
typescript
import { TemplateEngine } from "@buntok/core/template";
const engine = new TemplateEngine();
// Register partials
engine.registerPartial("header", "<h1>{{ title }}</h1>");
engine.registerPartial("footer", "<p>© 2024 Company</p>");
// Use in templates
const html = engine.render(`
{{> header }}
<p>Main content</p>
{{> footer }}
`, { title: "Welcome" });Helpers#
Custom functions for data transformation.
typescript
const engine = new TemplateEngine();
engine.registerHelper("formatDate", (date: unknown) => {
return new Date(date as string).toLocaleDateString("id-ID");
});
engine.registerHelper("uppercase", (str: unknown) => {
return String(str).toUpperCase();
});
const html = engine.render(
"{{ uppercase name }} - {{ formatDate date }}",
{ name: "budi", date: "2024-01-15" }
);
// → "BUDI - 15/1/2024"Comments#
typescript
render("Hello {{! this is a comment }}World", {});
// → "Hello World"Strict Mode & Error Detection#
By default, missing variables throw an error with helpful suggestions.
typescript
render("Hello {{ usre.name }}", { user: { name: "Budi" } });
// → Error: Variable 'usre.name' not found in context.
// Available keys: user
// Did you mean: 'user.name'?typescript
// Lenient mode - missing variables become empty string
const engine = new TemplateEngine({ strict: false });
engine.render("Hello {{ missing }}", {});
// → "Hello "Compile & Reuse#
Pre-compile templates for better performance when rendering multiple times.
typescript
const engine = new TemplateEngine();
const compiled = engine.compile("Hello {{ name }}!");
// Reuse without re-parsing
compiled({ name: "A" }); // → "Hello A!"
compiled({ name: "B" }); // → "Hello B!"Full Email Template Example#
typescript
import { render, TemplateEngine } from "@buntok/core/template";
const engine = new TemplateEngine();
engine.registerPartial("header", '<div class="header"><h1>{{ company }}</h1></div>');
engine.registerHelper("formatCurrency", (val: unknown) => `Rp ${Number(val).toLocaleString()}`);
const template = `
{{> header }}
<h1>Invoice #{{ invoice.number }}</h1>
{{#if invoice.paid}}
<p style="color: green;">✓ Paid</p>
{{else}}
<p style="color: red;">Please pay by {{ invoice.dueDate }}</p>
{{/if}}
{{#each invoice.items}}
<div>{{ name }} - {{ formatCurrency price }}</div>
{{/each}}
<p>Total: {{ formatCurrency invoice.total }}</p>
`;
const html = engine.render(template, {
company: "My Company",
invoice: {
number: "INV-001",
paid: false,
dueDate: "2024-02-01",
items: [
{ name: "Product A", price: 150000 },
{ name: "Product B", price: 250000 },
],
total: 400000,
},
});API Reference#
| Function | Description |
|---|---|
| render(template, context) | Render a template with context data |
| registerPartial(name, template) | Register a reusable partial |
| registerHelper(name, fn) | Register a helper function |
| new TemplateEngine(options) | Create engine instance with options |
| engine.compile(template) | Pre-compile template for reuse |