Templating engine? No thanks.

by Marcel Garus · 2021-11-12 · 2 minute read · this blog · available at mgar.us/no-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:

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

  2. 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 Articles, then turns each of them into some small HTML snippet using the article_teaser function and then it joins all of them and puts them in the body of a page. I can just apply my full knowledge of Rust's Iterator 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?

Thanks for reading!

If you liked this article, feel free to share it using this shortlink:

By the way, I wrote other articles about this blog. Here's an article I recommend:

On Developing This Blog

2021-08-14 · 1 minute read · this blog

I created the blogging server that hosts this page with my bare hands. Well, the HTTP request handling software at least. And I have to say; I thoroughly enjoyed it!