Templating engine? No thanks.
Why this blog doesn't use a templating engine
Here is the Rust code that produces the page you're currently reading (at least at the time of writing). Some time ago, a friend of mine asked me why I used this home-grown templating mechanism instead of a standard like mustache.
Admittedly, this might look very hacky on first impression:
async fn article_full(article: &Article, suggestion: &Article) -> String {
fs::read_to_string("assets/article-full.html")
.await
.unwrap()
.fill_in_article(&article)
.replace("{{ suggestion-key }}", &suggestion.key)
.replace("{{ suggestion-title }}", &suggestion.title)
}
It's just loading the template file and then replacing some strings! (If you wonder about fill_in_article(&article)
, that also does nothing more than replacing some strings.)
But I still think it's more elegant than using some full-blown templating engine like mustache for two reasons:
It's pure Rust. Depending on one less library means you have to understand one less library. In fact, you can understand this code just by having a rough grasp of the standard library. I'm no Rust magician myself, but I still believe this is the easiest to understand version of the code that can possibly exist, given no prior templating knowledge.
It's type-safe! Instead of having some weird looking syntax like
{{#condition}} stuff {{/condition}}
in the HTML code, I instead take advantage of Rust's full type safety! Just take a look at how the main page is constructed:pub async fn blog_page(articles: Vec<Article>) -> String { let mut teasers = vec![]; for article in articles { teasers.push(article_teaser(&article).await); } page( "Blog", &metadata(...), &itertools::join(teasers, "\n"), ) .await }
That's just marvelous! It takes a list of
Article
s, then turns each of them into some small HTML snippet using thearticle_teaser
function and then it joins all of them and puts them in the body of apage
. I can just apply my full knowledge of Rust'sIterator
protocol without doing any weird hacks in HTML.
And it's not just me: Most modern UI frameworks – Flutter, React, Jetpack Compose, SwitftUI – try to move the power of constructing UI into the code itself instead of keeping it in a separate language.
So, the next time someone offers you a templating library, you might want to step back a bit and think: What's the benefit of adding this other abstraction? Is this really making my life easier overall?