Closure Templates for AppJet
For a new web project we decided to go for a template solution as a replacement for AppJet's print tags. The print tags are fine, they ensure well-formed HTML code and are easy to handle. By using them however HTML code tends to get mixed up with application logic, something we didn't want for the new site.
EJS in AppJet 2
AppJet 2 (Etherpad) uses EJS, an engine normally used on the client side. By using AppJet's JavaScript engine these templates can be evaluated at the server side. A great solution.
Closure Templates
After evaluating different templating tools we decided to give Closure Templates a try. Google is making some real strong statements about it:
- Easy to read. You can clearly see the structure of the output HTML from the structure of the template code. Messages for translation are inline for extra readability.
- Designed for programmers. Templates are simply functions that can call each other. The syntax includes constructs familiar to programmers. You can put multiple templates in one source file.
- Battle-tested. Closure Templates are used extensively in some of the largest web applications in the world, including Gmail and Google Docs.
The engine comes in two flavors, a compiler that generates client-side JavaScript and a Java library for server-side use and that one is a perfect fit for AppJet which is running on the JVM.
The Solution
We added the Closure Java library and have built a corresponding JavaScript library named lib-soy. Have a look at it to see how the templates are separated from the code in an extra section called /* appjet:soy */. The lib also includes the original sample from Google's tutorial:
/**
* Greets a person and optionally a list of other people.
* @param name The name of the person.
* @param [additionalNames] The additional names to greet.
*/
{template .helloNames}
// Greet the person.
{call .helloName data="all" /}
// Greet the additional people.
{foreach $additionalName in $additionalNames}
{call .helloName}
{param name: $additionalName /}
{/call}
{if not isLast($additionalName)}
// break after every line except the last
{/if}
{ifempty}
No additional people to greet.
{/foreach}
{/template}This example demonstrates some important concepts of Closure Templates. Hierarchical templates, template parameters, iteration and conditional templates. Enough to get started. Just include lib-soy and you are ready to use soy templates in your own apps.