Improving the syntax of EJS templates

[2016-09-10] dev, javascript
(Ad, please don’t block)

I really like the way EJS templates work, because the meta-language (loops, if-then-else, etc.) is just JavaScript. This blog post describes ideas for improving their syntax.

EJS templates  

This is an example of an EJS template:

<ul>
<% for(var i=0; i<supplies.length; i++) { %>
   <li><%= supplies[i] %></li>
<% } %>
</ul>

I see two problems with this template:

  1. It outputs empty lines for line 2 and 4.
  2. The delimiters <% and %> make the template look cluttered.

Suppressing whitespace  

The first problem can be fixed by using the delimiters <%_ and _%> which suppress any whitespace generated by that line:

<ul>
<%_ for(var i=0; i<supplies.length; i++) { _%>
   <li><%= supplies[i] %></li>
<%_ } _%>
</ul>

Better control flow syntax  

If control flow syntax is enabled by a single character at the beginning of a line then the template looks much nicer:

<ul>
# for(var i=0; i<supplies.length; i++) {
   <li><%= supplies[i] %></li>
# }
</ul>

The way to get this syntax is via a work-around – use a regular expression to convert:

# foo

to:

<%_ foo_%>

For example:

template = template.replace(/^[ \t]*#(.*)$/mg, '<%_$1_%>');

This regular expression allows the # to be indented:

<html>
    <body>
        # for(var i=0; i<supplies.length; i++) {
           <li><%= supplies[i] %></li>
        # }
    </body>
</html>

One more improvement  

Additionally, there is an issue for letting people change the delimiter <% to something different. Then the template could look like this:

<ul>
# for(var i=0; i<supplies.length; i++) {
   <li>{{= supplies[i] }}</li>
# }
</ul>

I find that easier to read, given that the delimiters are surrounded by HTML with lots of angle brackets.