Sailfish Template Engine

repository·main·Indexed 21 days ago

https://github.com/rust-sailfish/sailfish

A small, fast, and type-safe template engine for Rust with syntax inspired by EJS. Sailfish features statically compiled templates, direct Rust integration, and support for both simple field access via TemplateSimple and advanced logic via the Template derive macro. It includes built-in filters, template inclusion via the include! macro, and configurable rendering options through attributes or a sailfish.toml file. Requires Rust 1.89 or later.

Tokens
9K
Snippets
43
Records
57
Agent score
73%

What's inside Sailfish

  1. Introduction to Sailfish Template Engine

    main

    Sailfish is a lightweight, high-performance template engine for Rust designed for rapid development and rapid rendering.

    Key characteristics include:

    • Type Safety: Templates are statically compiled, ensuring rendering is always type-safe.
    • Rust Integration: You can write Rust code directly inside templates, supporting syntax like struct definitions, closures, and macro invocations.
    • Performance: Extremely fast rendering with minimal dependencies (<15 crates).
    • Extensibility: Supports built-in filters.

    For detailed technical specifications, refer to the sailfish API docs.

  2. Use the Template trait for reusable templates

    main

    The Template trait provides a render() method that borrows &self instead of consuming the object. This is useful when you need to render the same template multiple times using the same struct instance. Like TemplateOnce, the Template trait can be implemented using a derive macro.

    Note: When using the derived Template trait, you cannot move fields out of the struct within your template logic (e.g., using them in a for loop that consumes the iterator), as the method only has a shared reference to self.

    pub trait Template {
        fn render(&self) -> RenderResult;
    }
  3. Planned features for Sailfish

    main

    Sailfish is in early-stage development. The following features are currently being discussed via RFCs (Request for Comments) and are not yet supported:

    • Template trait: A trait that allows rendering without consuming the template instance.
    • Template inheritance: Support for blocks, partials, and other inheritance patterns.
  4. Use a sailfish.toml configuration file

    main

    Sailfish supports global and local configuration via a sailfish.toml file.

    File Discovery

    Sailfish searches for sailfish.toml in the same directory as your Cargo.toml and all parent directories, following this order (from deepest to root):

    1. /foo/bar/baz/sailfish.toml
    2. /foo/bar/sailfish.toml
    3. /foo/sailfish.toml
    4. /sailfish.toml

    Precedence Rules

    • Directory Precedence: Values in deeper directories take precedence over values in ancestor directories.
    • Attribute Precedence: Values specified in #[template] derive options take precedence over values in the sailfish.toml configuration file.
  5. Install Sailfish syntax highlighting for Vim using dein.vim

    main

    To install Sailfish template syntax highlighting using the dein.vim plugin manager, add the following line to your Vim configuration. You must specify the rtp (runtime path) to point to the syntax/vim directory within the repository.

    call dein#add('rust-sailfish/sailfish', {'rtp': 'syntax/vim'})
  6. Apply filters in Sailfish templates

    main

    Filters are used to format the rendered contents of an expression. You can control whether the output is HTML-escaped or not using different tag syntaxes.

    • Apply filter and HTML escaping: Use <%= expression | filter %>. This is the default behavior for standard expressions.
    • Apply filter only (no escaping): Use <%- expression | filter %>. Use this when you want the raw output of the filter to be rendered directly into the HTML without escaping special characters.
    // Escaped output
    <%= "foo\nbar" | dbg %>
    
    // Unescaped output
    <%- expression | filter %>
  7. Render a template using TemplateSimple

    main

    To render a template in Rust, follow these steps:

    1. Import the trait: Use sailfish::TemplateSimple.
    2. Define the template struct: Use the #[derive(TemplateSimple)] macro on a struct. Use the #[template(path = "...")] attribute to point to your .stpl file. The struct fields represent the data available within the template context.
    3. Render the data: Instantiate the struct with your data and call the .render_once() method.

    Note: .render_once() returns a Result, so you should handle potential errors (e.g., using .unwrap() for simple examples).

    use sailfish::TemplateSimple;
    
    #[derive(TemplateSimple)]
    #[template(path = "hello.stpl")]
    struct HelloTemplate {
        messages: Vec<String>,
    }
    
    fn main() {
        let ctx = HelloTemplate {
            messages: vec![String::from("foo"), String::from("bar")],
        };
    
        // Render the template with the given data
        println!("{}", ctx.render_once().unwrap());
    }
  8. Prepare a Sailfish template file

    main

    To use Sailfish, you must create a template file (typically with a .stpl extension) inside a templates/ directory located in your project root (the same directory as Cargo.toml).

    Example template content (templates/hello.stpl):

    <html>
      <body>
        <% for msg in &messages { %>
          <div><%= msg %></div>
        <% }
      </body>
    </html>

    Your project structure should look like this:

    Cargo.toml
    src/
        (Source files)
    templates/
        hello.stpl