Thanks to visit codestin.com
Credit goes to github.com

Skip to content

jonahlund/vy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

84 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vy

crates.io docs.rs build license: MIT

A convenient, type-safe HTML templating library for Rust

Usage

use vy::prelude::*;

// Create a typical HTML page
fn page(content: impl IntoHtml) -> impl IntoHtml {
    (
        DOCTYPE,
        html!(
            head!(
                meta!(charset = "UTF-8"),
                title!("My Title"),
                meta!(
                    name = "viewport",
                    content = "width=device-width,initial-scale=1"
                ),
                meta!(name = "description", content = ""),
                link!(rel = "icon", href = "favicon.ico")
            ),
            body!(
                h1!("My Heading"),
                content
            )
        ),
    )
}

// Here's how to express common patterns in the VY tuple-based syntax
fn patterns(items: Vec<String>, condition: bool, maybe_some: Option<String>) -> impl IntoHtml {
    (
        // for loop
        items.into_iter().map(|item| li!(item)),
        // if-then-else
        condition.then_some(i!("condition is met")),
        (!condition).then_some(b!("condition is NOT met")),
        // if-let
        maybe_some.map(|inner| i!(inner)),
    )
}

assert_eq!(
    patterns(vec!["foo".into(), "bar".into()], true, Some("some".into())).into_string(),
    "<li>foo</li><li>bar</li><i>condition is met</i><i>some</i>"
);

assert_eq!(
    patterns(vec![], false, None).into_string(),
    "<b>condition is NOT met</b>"
);

Key features to note:

  • Tag macros: HTML elements are created using dedicated macros.
  • Inline attributes: Attributes are declared directly within macro bodies using key = value syntax.
  • Zero wrapping: No need for container macros – elements compose naturally.
  • Void element support: Automatically handles self-closing tags like <meta>, <img>, etc.

Syntax

The macro grammar follows this pattern:

element := [attribute],* [content],*

content := expression
attribute := name['?'] '=' expression
name := identifier | text

Key design choices

  • Parenthesis-based: Works with rustfmt formatting constraints.
  • Reserved word handling: Attributes like type and for use string syntax, e.g., "type" = ".." instead of type = "..".
  • Optional attributes: ? marks optional attributes (e.g., class? = Some("foo") or disabled? = true).

Why this syntax?

The macro design balances several constraints:

  • Compatibility with Rust's syntax tree.
  • rustfmt compatibility (requires parenthesis syntax, e.g., div!() instead of div!{}).
  • Natural HTML-like authoring experience.
  • Compile-time validation.

Escaping

Escaping is done automatically, but can be opted out by wrapping a type with PreEscaped(..).

Performance

vy utilizes a few practices for fast rendering times:

  • Pre-calculated sizing: HTML output size is estimated before allocation.
  • Single-allocation rendering: Most templates render in one memory allocation.
  • Zero-cost composition: Macros expand to tuple-based [IntoHtml] types without closures.

Contributing

You can run ./.pre-commit.sh before sending a PR, it will check everything the CI does.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •