Should You Use The Template Element?
The latest Windows update (Threshold 2) featured new standards support in Edge. While there are many new features and bug fixes one that got me a little energized is the TEMPLATE element. I had been waiting for Edge to add TEMPLATE element support for a while now because I use HTML templates extensively in my web applications.
I had held off doing any serious experimenting with the TEMPLATE element until it was commonly supported across browsers. With Edge that completes all the current main stream browsers so I decided to see what it would take to upgrade my infrastructure from SCRIPT elements to TEMPLATE elements. Spoiler, I was very disappointed with my discovery.
The SCRIPT Element Hack
I first started using client-side rendering sometime back in late 2008 and created my first formal technique about a year later. This technique used what I call the SCRIPT hack. This is where you wrap an HTML template within a SCRIPT element, but set the type to something custom.
<script id="productGridGroup" type="text/x-simpleTemplate-template"><%for(var index in this.groups) {%><div class="item-grid-group"><h1 class="item-grid-group-title"><%this.groups[index].Name%></h1><div class="item-grid-group-items group-items-<%this.groups[index].Name%>"></div></div><%}%></script>
This technique does two things, keeps the browser from rendering the markup and causes the browser to not evaluate the content as a script. These two features are important and I thought that is what the TEMPLATE element would do.
If template markup is rendered by the browser the user will see it. Pre-rendering is not desirable because you want to merge data with the template to generate the markup to add to the DOM on the fly. This creates confusion in the customer's mind because they see this content that makes no sense with the application state. It also adds more elements for the browser to render, which means it renders slower.
While you could hide your templates by setting the CSS display:none property and value on the wrapping element, this does not solve all our problems. Another negative when a template is rendered is downloading images, which can take up valuable HTTP connections and cause your application to boot slower.
Using a SCRIPT element prevents the markup from being rendered and images from downloading because the browser sees these blocks as scripts. However now the browser thinks the element's content is a script and attempts to parse the content as a JavaScript, which it is not. While most templates include a mixture of script and markup, it is not a script in the traditional sense.
This is why you should always set the type attribute to a custom value. When the browser evaluates the type and does not recognize it as a JavaScript type it ignores the content and does not attempt to evaluate the contents. In essence the browser looks at the SCRIPT templates as some sort of inert content that it does nothing. The elements remain in the DOM, but are not styled, rendered or evaluated, exactly what we need.
If you have read my High Performance Single Page Web Application book, read this Blog or attended one of my SPA presentations over the past few years you know I have relied on the SCRIPT hack to drive my SPAs. Using the SCRIPT hack is just that a hack. It is not natural, but a trick we can leverage to enable our modern, AJAX driven applications.
The TEMPLATE Element, A New Hope
The Template element promised to make native what the Script tag hack has been accomplishing for the past 8 or 9 years. This means the markup within the Template element is not rendered and any assets, like images are not requested. This means the Template contents are inert and do not cause any real performance hits, which is what we want. The advantage the Template element has over the Script hack is it is semantically correct.
I have been excited about the promise of a semantic element to help drive rich modern web applications. And if the TEMPLATE element did these two things everything would be great. But alas it does more. This is where the story derails and we find ourselves in the pit of disappointment.
Last month I peel off time one weekend to refactor my Fast Furniture application to use the TEMPLATE element. I thought it would not be much more than just a global search and replace of SCRIPT elements for TEMPLATE elements. After doing this quick exercise I loaded the application and saw it blow up. My console was littered with a see of blood red error messages.
I made the mistake of not reading the instructions and when I did I sort of glossed over the fine print. You see the TEMPLATE element is not a semantic replacement for the SCRIPT element, it adds complications to the work flow.
First you cannot use the TEMPLATE element as a template wrapper, it needs to be cloned. I find this rather odd and in contrast to what I have found to be a SPA best practice.
I have built several rather large SPAs, and as such have dealt with hundreds of templates in an application. I lazy load templates, scripts, CSS etc. I have sophisticated techniques to ensure the application loads quickly and runs super fast. This involves parsing and removing my views, layouts and templates from the DOM during the boot process and caching these components in browser storage.
The TEMPLATE element adds extra requirements that make this technique difficult if not impossible. I spent the better part of a weekend trying to get this to work and came up with nothing. If you read the instructions in the HTML5 Rocks article you should see the TEMPLATE element must be part of the DOM. Furthermore the element must be cloned before it is used.
This means a SPA would require potentially hundreds of templates remain in memory. You might be saying, so what? I know I did when I first started building Single Page Applications. Then I tried to run them on phones and I learned quickly you need to keep the DOM very thin to achieve the desired run-time performance. Large DOM trees are sluggish and users hate that experience. My technique cleans the DOM of application templates, helping it execute as fast a possible when the user interacts with the content.
Second I have gone through various gyrations of templating and binding techniques. I started with John Resig's micro-templating back in 2009, moved on to MUSTACHE, Handlebars, then MVVM binding. I have made the full circle and come back to micro-templating, which is also employed by Underscore and Backbone. At its essence it is string building, the fastest way to merge markup with data.
I could have lived with a new technique that required cloning, except I was unable to get that to work without injecting the template back in the DOM. I thought that was just a silly waste of time and resources. Why can't I just access the template's content and do what I have been doing?
To further complicate matters I could not use my templates. One of the complaints about 'Push' templates, or string building templates is XSS concerns. This means a user could submit unescaped markup that might execute an evil script.
Of course this means you need to design your code rather carelessly, which can happen even to the best of us. But the reality is you can escape any submitted content as part of your logic process. Plus your application should be smart enough to know who is submitting content and control where that content goes. So I take a little exception to this objection, but understand the concern. This is where the template element tries to do too much, it expanded its scope beyond it's requirements.
Unfortunately the TEMPLATE element only returns an escaped version of the template, which means you cannot use a field based merge technique, which again is my preferred technique. Instead you must have a set of heavy JavaScript, be that a library/framework or some ugly custom routine to set the template's values. This means lots of overhead, which I simply cannot afford.
Simply put, this made the TEMPLATE element unusable. A very sad disappointment.
What About Legacy Browsers
Still thinking about using the TEMPLATE element? But what about those folks still using Internet Explorer or Opera Mini? And then there is Android.
First Opera Mini. Unless I have significant traffic from Opera Mini I am not going to consider it. However if I do have traffic I would implement some sort of core site option, but that is outside the scope of this article.
As you know Internet Explorer is not going to receive any new features and standards support, hence no Template element. In fact in less than a month IE 10 and below are no longer supported. That alone winnows the support surface area to be concerned with. But there will still be millions if not a billion or so Internet Explorer users running around.
First, Windows Phone. It is around 3-5% market penetration, which sadly is not much. I hope most will be able to upgrade to Windows 10 soon, which means they will be using Edge, problem solved. But let's say it is 50% (being generous and using a very round number). Now we have about 2% of the mobile world on an obsolete browser that does not support Template.
Next is desktop, dominated by Windows. While most consumers use Chrome and Firefox (and a growing number Edge) as their desktop browser many enterprises do not. They are concerned about their legacy business software failing in these modern environments. Even with Microsoft deprecating all but Internet Explorer 11 next month many will hang on to older versions of Internet Explorer.
A large majority of these systems are not being upgraded to Windows 10, which means they have no access to Edge and the TEMPLATE element. And remember this is a corporate environment so they are more likely to not be able to use Chrome, Opera or FireFox. These end users are stuck with Internet Explorer even if it is 11. This is billions of desktop computers.
Finally what about Android. Sure you are using Chrome on your droid, but most use the default browser. The default browsers do not support the TEMPLATE element. And of course you would also need a newer Android, how many are still using a Gingerbread or early Android. Again too many.
Conclusion
While I had high hopes for the TEMPLATE element adding semantic goodness to the world of Single Page Web Applications it went too far and made itself useless. Instead of being a nice, simple solution it does too much and makes itself a problem rather than a solution.
The nature of the TEMPLATE element also means it is not an easy polyfil, images will still get downloaded, so legacy browser support is not feasible.
The combination of doing too much and legacy browser support make the TEMPLATE element a bad idea. Stick with the SCRIPT hack and you will be able to continue to build high performance single page web applications.