The problems with creating a new template language
utcc.utoronto.ca
utcc.utoronto.ca
Neither of these are true anymore, so it is time we let template languages go.
The essence of templating is string interpolation. That is what ERB, Jade, HAML and similar languages do. ES6's Template Strings are fantastic at this. They are multi-line, and they allow interpolation.
Even if we supposed that the notion of separation of view and view-logic was a reasonable one, the baggage that a dedicated templating language brings in is simply not worth it.
Here are examples of the baggage: 1) the choice of picking a templating language is almost of a religious nature (HAML vs ERB).
2) Custom syntax and needs for each language - the `surround`, `suffix`, and `precede` helpers in HAML.
3) Templating languages almost always reinvent programming constructs poorly. Greenspun's tenth rule is really apt here:
Any sufficiently complicated templating language contains an ad hoc, informally-specified, bug-ridden, slow implementation of a turing complete programming language.
These days I rely a lot on JSX, which is rigorous and catches errors, thanks to compile-time parsing, and well-integrated into the language so that I can use programming language abstractions without wringing them through ill-defined extension points in a templating language.
Template language is useful not because it allows to do things, but because it limits what can be done.
Code/view reuse for example is done through partials in template languages: you can either learn `<%= render partial: "filename" %>` syntax for ERB (with Rails), or `include filename` syntax for JADE, or the `{% include template_name %}` syntax in Django.
Or you could simply use functions: compose them, curry them, put them in objects and call them, and even remote execute them; it is all code.
Logic is similar: every template language has their own syntax for conditionals and loops. Learning these does not teach us anything new nor make us better at our craft. These are simply useless tediums.
Another pet peeve is Template Inheritance. Jade has `block` and `extends` keywords; RABL similarly has an `extend` keyword. Programming languages have an arguably better way to do inheritance.
This is my rule of thumb: if a library/template language brings its own semantics for inheritance, be wary.
I like that in templates, string handling is _enforced_ to be different. For example, when you manipulate strings in template, you can be reasonably sure all output is escaped, unless you specify otherwise in a very few precise cases with explicit syntax.
A good template language allows you to create/limit available tools/helpers for your particular project. That is especially important in larger projects and larger teams, where everyone is not immediately expected to know intended good practice to follow. Creating DSL in template _is_ a way of documenting intended good practice.
A good template language does not pretend not to be turing-complete: instead, it provides comprehensive error handling and error messages, so that users know exactly where some error or type occurred.
One more reason to use the language is because it is a language. If someone used something like Django, the Twig will be quite familiar and easy to pick up.
Template engine can optimize-away, pre-compile things, just like languages do.
With separate template language you don't need to recompile whole build if you change a template (presuming hosting language is compiling to binary and template engine is interpreted).
Full disclosure: I am currently rewriting Twig in another language, and believe it's completely worth the effort.
In the beginning, it would be a text file with a few string interpolation in between, which means we insert logic inside content, and it can remain in the native format.
But over time, as in the HTML generated for web apps, the balance of content inverses. What begins mostly as some logic inside predominantly static content, becomes some static content inside a lot of logic. At that point, it is best to make code the primary medium.
IMHO the best templating language available widely at this moment is mustache (and/or handlebars) as it's almost as simple as it can get and that's the way it should be. Logic should be at code and templates should just render text given to them.
Recently however we had to push something out really quickly, and opted to avoid our own pipe line in order to put out some raw html, css, and js, very quickly.
Although I cannot imagine how it would be, I wonder if their will be some kind of process in the near future that abstracts away the build pipe line an allows me to continue to write jade/scss/es6 without having to put any effort in putting it in production..
A secondary reason is to constrain your users so they don't end up writing constructs that will be impossible to manipulate with tooling. Early in Bazel's [2] history at Google, BUILD files were just ordinary Python, and you could use any Python code you wanted, and all that mattered were the calls you made into the build rules. This worked great, with people writing all sorts of list comprehensions and conditionals to minimize code duplication. And then tools came out to reformat BUILD files, and automatically query for dependencies, and detect dead binaries, and all sorts of other cool stuff. The tools were a lot more useful than the ability to include arbitrary code, but (because of the halting problem) they would choke whenever they encountered arbitrary flow constructs. So now arbitrary code is limited to the portions of the build system that explicitly allow it.
The EDSL approach (where you just use a regular programming language and a bunch of calls into the engine) can be a good idea, but you give up a lot in tooling. Usually it's most useful in the early stages of a project, where you don't have manpower to write the tooling anyway, and then becomes a legacy hassle as you assign more engineers, write more code, and get more leverage from writing tools.
[1] https://github.com/google/gumbo-parser
[2] http://bazel.io/
Because you might want an integer or a float type.
Because you might want to be able to test the logic of your code on one environment, the only environment where it will be run.
Because you might want a reasonable dependency tree.
Because you might not want to rewrite portions of your code to run them on the server side.
I could go on.