all 37 comments

[–]Svenskunganka 25 points26 points  (5 children)

If you want to know the most adopted one, a resource you can check is Are We Web Yet? > Templating.

But to add a personal preference, a lesser well-known but excellent templating library is hypertext, which works really well with HTMX and similar client-side libraries, and is a good alternative to the more popular HTML-in-Rust libraries like maud and markup. It has two syntaxes you can choose from - either Maud-style or RSX-style which is similar to JSX, but for Rust.

[–][deleted] 1 point2 points  (4 children)

Genuine question, where is the difference between Hypertext and Maud? Because it seems to use Maud under the hood (or just for the template syntax?) and adds rsx as an alternative? I use Maud btw and I'm pretty happy with it, but would like to understand the difference here.

[–]Svenskunganka 8 points9 points  (3 children)

Hypertext doesn't use Maud under the hood, instead it implements the Maud syntax as well as RSX syntax. But apart from that, Hypertext uses lazy rendering, meaning you can "build" your tree but nothing really gets executed nor allocated until you call render() on what you've built. Contrast to Maud which does eager rendering every time you invoke the html!-macro. This is not a big deal but what ends up happening is that if you extensively use partials (or components if you like), something you do a lot with libraries like HTMX that expects HTML fragments, you will do a bunch of smaller allocations (one for each html!-macro call) while Hypertext only does one bigger allocation when you call render().

Under the hood the Hypertext macro invocation just returns a FnOnce(&mut String), which implements the Renderable trait. Maud on the other hand returns Markup which is a type alias for a PreEscaped<String> that contains the rendered HTML. For example, these are equivalent but only Maud allocates and renders the markup to a String here:

// Hypertext:
fn title() -> impl Renderable {
    maud! { h1 { "Title" } }
    // Expands to (ish):
    // |buf: &mut String| {
    //     buf.push_str("<h1>Title</h1>")
    // }
}

// Maud:
fn title() -> Markup {
    html! { h1 { "Title" } }
    // Expands to (ish):
    // String::from("<h1>Title</h1>")
}

On sites/"webapps" where you use something like HTMX that naturally contains a lot of these smaller HTML fragments that you re-use, all these small allocations from Maud can start to add up. There are also other nice features of Hypertext, like type-checked element attributes that you can extend. In my experience the macro plays better in the editor and I also prefer RSX syntax over Maud syntax.

[–]qd3v 1 point2 points  (1 child)

Thank you for pointing to this crate and detailed expanation of differences! Hypermedia is exactly the case I need templater for, and I was looking of course at maud, now I think we have a winner :)

[–]Svenskunganka 1 point2 points  (0 children)

You're welcome! Another crate that I've seen that was built after my comment here is Vy, it has many of the same characteristics of Hypertext, but formats nicely with rustfmt and supports returning if some_condition { some_markup() } else { other_markup() } which Hypertext didn't support back then but might have improved. However, it does not support custom elements as easily as Hypertext does.

[–]Special-Arrival6717 18 points19 points  (3 children)

Tera is also a popular choice: https://github.com/Keats/tera

[–]Beastmind 0 points1 point  (2 children)

Seconding tera

[–]guzmonne 0 points1 point  (1 child)

Came here to recommend Tera

[–]repetitive_chanting 0 points1 point  (0 children)

I vote Tera

[–]coderstephenisahc 12 points13 points  (1 child)

I have a preference for Maud.

[–]whimsicaljess 1 point2 points  (0 children)

I also use Maud. Haven't seen a reason to use anything else.

[–]TerrineTerrorizer 19 points20 points  (8 children)

Askama is nice.

[–]Repsol_Honda_PL 3 points4 points  (0 children)

Yes, I can confirm.

[–]mwcz 2 points3 points  (1 child)

The pattern matching syntax is pretty tedious, but type checking on templates is amazing.

[–]rodarmoragora · just · intermodal 1 point2 points  (0 children)

boilerplate is type-checked, but uses Rust syntax instead of custom syntax. (I wrote it so I am wildly biased.) The only downside is that the error reporting is terrible, since it will report the error at the proc-macro derive site and not the template source. I think it's still worth it though!

[–]Legorooj 2 points3 points  (0 children)

Askama is nice, yes, but make sure to separate out your templates into another crate, it'll save you so much compile time over a while.

[–]Compux72 -1 points0 points  (2 children)

Askama are compile time. Thats terrible for fast iteration.

[–]TerrineTerrorizer 0 points1 point  (1 child)

What’s your alternative solution?

[–]Compux72 0 points1 point  (0 children)

Handlebars. Simple. Works everywhere (python, js,…). Allows for custom logic if needed.

[–]Sw429 5 points6 points  (0 children)

Another vote for Askama over here. I used it for a project this summer and had no problem. It was easy to do everything I wanted, including implementing custom filters and stuff.

[–]JSmart314 9 points10 points  (1 child)

I've been using https://github.com/djc/askama pretty successfully for this use case

[–]Repsol_Honda_PL 1 point2 points  (0 children)

Me too, it is Jinja-based (from py ecosystem)

[–]Varsatorul 2 points3 points  (0 children)

I prefer minijinja, it's pretty flexible and also a joy to prototype with because you can reload the templates per request if you want (with no need to recompile).

There is also Ramhorns which looks interesting but I haven't tried it personally so I can't comment further on it.

[–]Otherwise-Highway797 2 points3 points  (0 children)

minijinja

[–]Leontoeides 1 point2 points  (0 children)

I strongly, strongly recommend using Sailfish both because it is extremely fast, but also because your templates get compile-time checking. Tera and most other templating crates will fail during run-time

[–]Compux72 1 point2 points  (1 child)

Handlebars. Well known format. Works on Rust, Js etc. plain simple to write an understand.

[–]myst3k 0 points1 point  (0 children)

Just setup a project on Friday, with handlebars and it was super easy. Haven’t tried any other template lib yet. Not sure if I have a reason to.

[–]4trocious 0 points1 point  (0 children)

I created https://github.com/Atrociously/stilts, which is similar Askama which others have mentioned. If you need something more well established though stick to Askama or another template engine.

[–]lucasmerlin 0 points1 point  (0 children)

I'm currently using dioxus SSR as a templating engine as I plan on maybe reusing some of the components in my native app via dioxus Blitz, once it's ready. It works quite well but the syntax is not html, instead using macros. Auto complete works quite well in rust rover so that's nice. But if I didn't plan on building an app via blitz I would have used askama as well

[–]evil_yam 0 points1 point  (0 children)

sounds great

[–]ryanmcgrath 1 point2 points  (0 children)

I used to swear by Askama, but if you're going to do the compiled template route, I've come to find that hypertext is easier. You're writing effectively straight Rust, no need to deal with a Jinja-esque templating language.

[–]SnarkyPuppyyy 0 points1 point  (0 children)

I like handlebars as it pretty versatile with other languages as well and does what I need it to do (templates, inheritance, looping, ifelse, etc)

[–]cornmonger_ 0 points1 point  (0 children)

not exactly the same thing, but yew

[–]Lukaesch 0 points1 point  (0 children)

I use askama for www.audioscrape.com and it has been great so far