Last week I have been looking at various template processors for the Web apps I work on, Spacewalk and SUSE Manager.
Turns out that not only there is a big number of them, but they also significantly vary in their philosophy! Preferences and opinions dominate the choice as features are similar — so here’s my personal two cents.
PHP’s Smarty: the good-old way
I started looking at template engines back in 2004 when writing a CMS in PHP. Back then I chose Smarty, and it provided the usual amount of features like comments, control structures, functions, custom operators, etc.:
{foreach $foo as $bar} <a href="{$bar.zig}">{$bar.zag}</a> <a href="{$bar.zig2}">{$bar.zag2}</a> <a href="{$bar.zig3}">{$bar.zag3}</a> {foreachelse} There were no rows found. {/foreach}
Smarty has grown to be pretty complete functionality-wise, as template designers needs grew. In fact, an entire piece of documentation is devoted to compare the syntax with plain PHP!
I found this to be a pattern: when doing templates, sooner or later you end up needing a lot of logic and language syntax.
Note that I am not taking about controller logic leaking into the view, which is of course not good. I am talking about real presentation logic that should be in the view anyway.
Java’s JSP, JSTL and EL: over-engineering?
I don’t find JSP radically different from Smarty. Control structures are still there, and EL is added to again be able to add logic to the view (expressions become non trivial and comparison tables pop up in documentation; you can define your own functions in Java in case the provided ones do not suffice).
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <html> <head> <title><c:forTokens> Tag Example</title> </head> <body> <c:forTokens items="Zara,nuha,roshy" delims="," var="name"> <c:out value="${name}"/><p> </c:forTokens> </body> </html>
Aspects I don’t like:
- The templating library is made of a number of taglibs, which is not bad by itself but it often feels over-engineered;
- Pure XML syntax might be an interesting theorical idea, but it is bulky in practice.
Want to add an else statement? Be prepared to turn this:
<c:if test="${singular}"> pizza </c:if>
into this:
<c:choose> <c:when test="${singular}"> pizza </c:when> <c:otherwise> pizzas </c:otherwise> </c:choose>
Python’s Jinja: more good-old-style
Reading Jinja2 templates after JSP brings back some piece of mind, usually they are a lot easier to read.
<title>{% block title %}{% endblock %}</title> <ul> {% for user in users %} <li><a href="{{ user.url }}">{{ user.username }}</a></li> {% endfor %} </ul>
They don’t add much to the Smarty recipe for simple applications, but they add features for the advanced ones:
- most features can be turned off to be able to run untrusted templates;
- Jinja2 is actually implemented in more than Python, for example a Java implementation exists. That can be useful for cross-language projects.
I never had such requirements so far, but those features do sound handy in some circumstances.
Anyway, again we have a lot of advanced syntax for control structures and logic.
Javascript’s Mustache: getting rid of control structures?
Idea behind Mustache is that no logic should be in templates, period. So Mustache doesn’t expose any control structure and any expression logic by design: there are only tags “that” fulfil a similar role, in a more data-oriented way.
I found this to be a bit tricky to understand at first, the manpage does a good job in explaining this concept so I won’t repeat it here.
Personally I find this limiting, because sometimes I do want logic in the view and in templates. It is my job to make sure that this logic is not really leaking from the controller, but sometimes I just want it there – for example odd/even row coloring in tables (pre-CSS3).
node’s Jade: DRYing up HTML
If all you are doing is (X)HTML, then it might make sense to tailor the template language to make it less verbose.
Indeed tags are tedious to close and angle brackets are tedious to write, so why not using indentation instead? Enter Jade, for example:
doctype html html(lang="en") body h1 Jade - node template engine #container.col if youAreUsingJade p You are amazing else p Get on it!
I must say this feels much cleaner and easier to work with than good old markup. It also enforces indentation which is a good thing. But again special language is needed for control structures and expressions (see the reference).
Of course this only works when targeting HTML, if you need JSON or really anything else, you are out of luck here.
Ruby’s ERB: don’t duplicate the language!
Here we have something different: don’t try to create a new language in the template engine, just use the host language as it is, by surrounding it with marks!
What ERB does is to add markers to start and end Ruby sections in the middle of a template. Suddenly we don’t need to learn a new sublanguage with subpar tooling, subpar syntax, subpar documentation and so on. Just mix Ruby in freely:
<ul> <% for @item in @shopping_list %> <li><%= @item %></li> <% end %> </ul>
Of course this approach is more prone to abuse as far as logic leaking from controllers is concerned, but I don’t think a syntax barrier really helps anyway.
I like this solution.
Firstly, as I am typically working in “full-stack” tasks I am usually very familiar with the host language anyway, so it is natural to read. No third-language mental overhead.
Secondly, I like the fact of not being constrained by whatever limitation of the template engine language. With the full host language available, a solution is always possible.
ASP.NET’s Razor views: even lighter syntax
ASP.NET follows ERB from a design point of view with a twist: mix C# and HTML at will and have the compiler automatically distinguish them, at least in most cases where this is possible without ambiguity.
For ambiguous cases, introduce the @ operator t0 denote C# code. See this example:
<h3>Team Members</h3> string[] teamMembers = {"Matt", "Joanne", "Robert", "Nancy"}; foreach (var person in teamMembers) { <p>@person</p> }
OK, I am simplifying a bit here, but that’s the core concept and it works really well in practice according to my experience.
Something similar also exists in Java: the Rythm project.
Conclusion
I find the amount of different concepts in this area quite amazing. My personal preference at the moment is in general towards engines that expose the host language, preferably with minimal syntax overhead like Razor.
Sii il primo a lasciare un commento. Non essere timido!