Tera Template Engine
repository·master·Indexed 26 days ago
https://github.com/keats/teraA template engine for Rust inspired by Jinja2 and the Django template language. Tera provides a familiar syntax for blocks, loops, and variable interpolation, supporting features like template inheritance, custom filters, tests, and functions. It includes optional features for fast rendering, glob-based filesystem loading, and unicode support, with an additional `tera-contrib` crate for extended functionality such as base64 encoding, regex, and date handling.
What's inside Tera
- Tera is a template engine inspired by Jinja2 and the Django template language. While it shares a similar look and feel with these engines, it intentionally deviates from their specific implementations in many ways.
Use tera-contrib for additional Tera functions and filters
masterThe
tera-contribcrate provides extra functions, filters, and tests for the Tera template engine that require additional dependencies.Note that while the docstrings in
docs.rsuse the same names as the library implementations, you can register these extensions into your Tera instance using any name you choose.Tera Template Syntax and Delimiters
masterTera templates are text files where variables and expressions are replaced with values during rendering. The syntax is based on Jinja2 and Django.
By default, Tera uses these delimiters:
{{and}}for expressions{%and%}for statements{#and#}for comments
You can customize these using
Tera::set_delimiters.Use Expressions and Math in Tera
masterTera supports expressions for math, comparisons, and logic.
Math Operators
+(addition),-(subtraction),/(division),*(multiplication),%(modulo).
Comparison Operators
==,!=,>=,<=,>,<.
Logic Operators
and,or,not.
String Concatenation
Use the
~operator to concatenate strings, numbers, or idents. The result is always a string.{{ "hello " ~ 'world' ~ `!` }}Use the Spread Operator for Component Arguments
masterPass the contents of a map to a component using the
{...map}syntax. Note that the order of arguments determines precedence: later values override earlier ones.{# explicit wins (after spread) #} {{ <ui.button label="Test" {...defaults} variant="danger" /> }} {# spread wins (after explicit) #} {{ <ui.button label="Test" variant="primary" {...overrides} /> }}Migrate from Tera v1 to v2
masterTera v2 is a complete rewrite. Key changes include the removal of macros in favor of components, stricter undefined variable handling, and significant performance improvements (2-4x faster on average, up to 75x faster for intensive data manipulation).Assign Variables with Set and Set_Global
masterAssign values during rendering using
{% set %}.- Local Scope:
{% set my_var = "value" %}. In aforloop, the variable is only valid until the end of the current iteration. - Global Scope:
{% set_global my_var = "value" %}. This sets the variable in the global context, even when called inside aforloop. - Block Assignment: You can assign a block of content to a variable:
{% set hero | upper %} Hello {{ world }} {% endset %}- Local Scope:
Install Tera in Rust projects
masterTo use Tera in your Rust projects, add it to your
Cargo.toml. By default, it only pulls theserdedependency. You can enable optional features for additional functionality:fast: Speeds up template rendering.glob_fs: Allows loading templates from the filesystem using globs.unicode: Enables working with grapheme clusters instead of UTF-8 characters when iterating over strings.preserve_order: Maintains the insertion order for values.
For additional filters, functions, and tests that require third-party dependencies, use the
tera-contribcrate.tera = "2"Define and Use Components
masterComponents are first-class reusable units defined with
{% component %}.Defining a Component
{% component ui.button(label: string, variant: string = "primary", ...rest) %} <button class="btn btn-{{variant}}">{{label}}</button> {% endcomponent ui.button %}- Types:
string,bool,integer,float,number,array,map. - Spread: Use
...restto collect extra parameters into a map. - Metadata: You can attach metadata
{"key": "value"}after the signature, accessible via the Rust API.
Using a Component
Components can be used with self-closing tags or as block elements.
{# Self-closing #} {{<ui.button label="Click me" variant="secondary" />}} {# Block syntax (passes content to {{body}}) #} {% <ui.forms.widget title="My Title"> %} <p>Widget content</p> {% end <ui.forms.widget %>}- Types:
Integrate Tera in a Rust project
masterTo use Tera in your own Rust application, initialize a
Terainstance, add your templates usingadd_raw_template, and render them using aContextcontaining your data.use tera::{Tera, Context}; let mut tera = Tera::default(); tera.add_raw_template("base.html", include_str!("base.html"))?; tera.add_raw_template("components.html", include_str!("components.html"))?; tera.add_raw_template("dashboard.html", include_str!("dashboard.html"))?; let mut context = Context::new(); context.insert("site_name", "My Dashboard"); context.insert("orders", &vec![/* order data */]); context.insert("products", &vec![/* product data */]); // ... more data let html = tera.render("dashboard.html", &context)?;Template Inheritance with Blocks
masterTera uses a base/child inheritance model similar to Jinja2.
Base Template
Define placeholders using
{% block name %}...{% endblock name %}.Child Template
Use
{% extends "base.html" %}as the first line. Override blocks using{% block name %}. Use{{ super() }}to include the content from the parent block.{% extends "base.html" %} {% block content %} <h1>Child Content</h1> {{ super() }} {% endblock content %}Use Rest Parameters (`...attrs`) in Components
masterComponents can use...attrsto collect additional keyword arguments into a single object, allowing for flexible attribute passing likeclassordisabled.