Tera Template Engine

repository·master·Indexed 26 days ago

https://github.com/keats/tera

A 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.

Tokens
12.4K
Snippets
42
Records
78
Agent score
38%

What's inside Tera

  1. Overview of Tera template engine

    master
    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.
  2. Use tera-contrib for additional Tera functions and filters

    master

    The tera-contrib crate provides extra functions, filters, and tests for the Tera template engine that require additional dependencies.

    Note that while the docstrings in docs.rs use the same names as the library implementations, you can register these extensions into your Tera instance using any name you choose.

  3. Tera Template Syntax and Delimiters

    master

    Tera 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.

  4. Use Expressions and Math in Tera

    master

    Tera 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' ~ `!` }}
  5. Use the Spread Operator for Component Arguments

    master

    Pass 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} /> }}
  6. Migrate from Tera v1 to v2

    master
    Tera 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).
  7. Assign Variables with Set and Set_Global

    master

    Assign values during rendering using {% set %}.

    • Local Scope: {% set my_var = "value" %}. In a for loop, 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 a for loop.
    • Block Assignment: You can assign a block of content to a variable:
    {% set hero | upper %}
    Hello {{ world }}
    {% endset %}
  8. Install Tera in Rust projects

    master

    To use Tera in your Rust projects, add it to your Cargo.toml. By default, it only pulls the serde dependency. 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-contrib crate.

    tera = "2"
  9. Define and Use Components

    master

    Components 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 ...rest to 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 %>}
  10. Integrate Tera in a Rust project

    master

    To use Tera in your own Rust application, initialize a Tera instance, add your templates using add_raw_template, and render them using a Context containing 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)?;
  11. Template Inheritance with Blocks

    master

    Tera 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 %}