Javascript templating shootoff (extended)

JavaScript performance comparison

Revision 21 of this test case created by Jonathan Neal and last updated

Info

Many engines gathered across all revisions of the original shoot off.

DO NOT LINK TO RAW.GITHUB.COM -- It will NOT work in latest firefox versions

Please:

Libraries (in no particular order):

Preparation code

<!---------------------------------------->
<!-- EXTERNAL LIBRARIES HOSTED BY A CDN -->
<!---------------------------------------->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"></script>
<script src="http://documentcloud.github.com/underscore/underscore-min.js"></script>
<script src="https://github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>
<script src="http://cdn.kendostatic.com/2011.2.804/js/kendo.all.min.js"></script>
<script src="http://twitter.github.com/hogan.js/builds/1.0.3/hogan.js"></script>
<script src="http://beebole.com/pure/wp-content/themes/BeeBole-pure/libs/pure.js"></script>
<script src="http://akdubya.github.com/dustjs/lib/dust.js"></script>
<script src="http://sstephenson.github.com/eco/dist/eco.js"></script>
<script src="http://embeddedjs.com/javascripts/ejs_production.js"></script>
<script src="https://github.com/downloads/donyantony/cdnjs/runtime.min.js"></script>
<script src="http://terrainformatica.com/kite/kite.js"></script>
<script src="http://borismoore.github.com/jsrender/jsrender.js"></script>
<script src="http://satchmorun.github.com/mote/mote.js"></script>
<script src="http://sandbox.thewikies.com/test/template.js"></script>

<!--------------------------->
<!-- DOM TEMPLATES         -->
<!--------------------------->
<div class="pure">
        <h1 class='header'></h1>
        <h2 class='header2'></h2>
        <h3 class='header3'></h3>
        <h4 class='header4'></h4>
        <h5 class='header5'></h5>
        <h6 class='header6'></h6>
</div>

<script>
/****************************************
 MASTER TEMPLATE DATA
 ****************************************/
window.tpl = {};
window.tpl.vars = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
};
window.tpl.vars2 = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   list: [{i:'1'}, {i:'2'}, {i:'3'}, {i:'4'}, {i:'5'}, {i:'6'}, {i:'7'}, {i:'8'}, {i:'9'}, {i:'10'}]
};  

/****************************************
 TEMPLATE ENGINES NOT HOSTED BY A CDN (github)
 ****************************************/
//Please minify any hard included library and note the version.

//Resig Template Function (modified to support ')
function tmpl(a){var b="var p=[];"+"with(obj){p.push('"+a.replace(/[\r\t\n]/g," ").replace(/'(?=[^#]*#>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<#=(.+?)#>/g,"',$1,'").split("<#").join("');").split("#>").join("p.push('")+"');}return p.join('');";return new Function("obj",b)}

//Resig modified template function (no "with" block)
function tmpl2(a){var b="var p=[];"+"p.push('"+a.replace(/[\r\t\n]/g," ").replace(/'(?=[^#]*#>)/g,"\t").split("'").join("\\'").split("\t").join("'").replace(/<#=(.+?)#>/g,"',$1,'").split("<#").join("');").split("#>").join("p.push('")+"');return p.join('');";return new Function("data",b)}

//Mustache 5.0 dev
var Mustache=(typeof module!=="undefined"&&module.exports)||{};(function(w){w.name="mustache.js";w.version="0.5.0-dev";w.tags=["{{","}}"];w.parse=m;w.compile=e;w.render=v;w.clearCache=u;w.to_html=function(A,y,z,B){var x=v(A,y,z);if(typeof B==="function"){B(x)}else{return x}};var s=Object.prototype.toString;var f=Array.isArray;var b=Array.prototype.forEach;var g=String.prototype.trim;var i;if(f){i=f}else{i=function(x){return s.call(x)==="[object Array]"}}var r;if(b){r=function(y,z,x){return b.call(y,z,x)}}else{r=function(A,B,z){for(var y=0,x=A.length;y<x;++y){B.call(z,A[y],y,A)}}}var k=/^\s*$/;function c(x){return k.test(x)}var p;if(g){p=function(x){return x==null?"":g.call(x)}}else{var n,h;if(c("\xA0")){n=/^\s+/;h=/\s+$/}else{n=/^[\s\xA0]+/;h=/[\s\xA0]+$/}p=function(x){return x==null?"":String(x).replace(n,"").replace(h,"")}}var d={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function o(x){return String(x).replace(/&(?!\w+;)|[<>"']/g,function(y){return d[y]||y})}function l(D,F,G,z){z=z||"<template>";var H=F.split("\n"),x=Math.max(G-3,0),A=Math.min(H.length,G+3),y=H.slice(x,A);var E;for(var B=0,C=y.length;B<C;++B){E=B+x+1;y[B]=(E===G?" >> ":"    ")+y[B]}D.template=F;D.line=G;D.file=z;D.message=[z+":"+G,y.join("\n"),"",D.message].join("\n");return D}function t(x,F,E){if(x==="."){return F[F.length-1]}var D=x.split(".");var B=D.length-1;var C=D[B];var G,y,A=F.length,z,H;while(A){H=F.slice(0);y=F[--A];z=0;while(z<B){y=y[D[z++]];if(y==null){break}H.push(y)}if(y&&C in y){G=y[C];break}}if(typeof G==="function"){G=G.call(H[H.length-1])}if(G==null){return E}return G}function j(A,x,E,z){var y="";var C=t(A,x);if(z){if(C==null||C===false||(i(C)&&C.length===0)){y+=E()}}else{if(i(C)){r(C,function(F){x.push(F);y+=E();x.pop()})}else{if(typeof C==="object"){x.push(C);y+=E();x.pop()}else{if(typeof C==="function"){var B=x[x.length-1];var D=function(F){return v(F,B)};y+=C.call(B,E(),D)||""}else{if(C){y+=E()}}}}}return y}function m(Z,B){B=B||{};var K=B.tags||w.tags,L=K[0],G=K[K.length-1];var y=['var buffer = "";',"\nvar line = 1;","\ntry {",'\nbuffer += "'];var F=[],aa=false,X=false;var V=function(){if(aa&&!X&&!B.space){while(F.length){y.splice(F.pop(),1)}}else{F=[]}aa=false;X=false};var S=[],P,C,M;var U=function(ab){K=p(ab).split(/\s+/);C=K[0];M=K[K.length-1]};var J=function(ab){y.push('";',P,'\nvar partial = partials["'+p(ab)+'"];',"\nif (partial) {","\n  buffer += render(partial,stack[stack.length - 1],partials);","\n}",'\nbuffer += "')};var x=function(ad,ab){var ac=p(ad);if(ac===""){throw l(new Error("Section name may not be empty"),Z,I,B.file)}S.push({name:ac,inverted:ab});y.push('";',P,'\nvar name = "'+ac+'";',"\nvar callback = (function () {","\n  return function () {",'\n    var buffer = "";','\nbuffer += "')};var E=function(ab){x(ab,true)};var T=function(ac){var ab=p(ac);var ae=S.length!=0&&S[S.length-1].name;if(!ae||ab!=ae){throw l(new Error('Section named "'+ab+'" was never opened'),Z,I,B.file)}var ad=S.pop();y.push('";',"\n    return buffer;","\n  };","\n})();");if(ad.inverted){y.push("\nbuffer += renderSection(name,stack,callback,true);")}else{y.push("\nbuffer += renderSection(name,stack,callback);")}y.push('\nbuffer += "')};var W=function(ab){y.push('";',P,'\nbuffer += lookup("'+p(ab)+'",stack,"");','\nbuffer += "')};var z=function(ab){y.push('";',P,'\nbuffer += escapeHTML(lookup("'+p(ab)+'",stack,""));','\nbuffer += "')};var I=1,Y,D;for(var Q=0,R=Z.length;Q<R;++Q){if(Z.slice(Q,Q+L.length)===L){Q+=L.length;Y=Z.substr(Q,1);P="\nline = "+I+";";C=L;M=G;aa=true;switch(Y){case"!":Q++;D=null;break;case"=":Q++;G="="+G;D=U;break;case">":Q++;D=J;break;case"#":Q++;D=x;break;case"^":Q++;D=E;break;case"/":Q++;D=T;break;case"{":G="}"+G;case"&":Q++;X=true;D=W;break;default:X=true;D=z}var A=Z.indexOf(G,Q);if(A===-1){throw l(new Error('Tag "'+L+'" was not closed properly'),Z,I,B.file)}var O=Z.substring(Q,A);if(D){D(O)}var N=0;while(~(N=O.indexOf("\n",N))){I++;N++}Q=A+G.length-1;L=C;G=M}else{Y=Z.substr(Q,1);switch(Y){case'"':case"\\":X=true;y.push("\\"+Y);break;case"\r":break;case"\n":F.push(y.length);y.push("\\n");V();I++;break;default:if(c(Y)){F.push(y.length)}else{X=true}y.push(Y)}}}if(S.length!=0){throw l(new Error('Section "'+S[S.length-1].name+'" was not closed properly'),Z,I,B.file)}V();y.push('";',"\nreturn buffer;","\n} catch (e) { throw {error: e, line: line}; }");var H=y.join("").replace(/buffer \+= "";\n/g,"");if(B.debug){if(typeof console!="undefined"&&console.log){console.log(H)}else{if(typeof print==="function"){print(H)}}}return H}function q(B,z){var y="view,partials,stack,lookup,escapeHTML,renderSection,render";var x=m(B,z);var A=new Function(y,x);return function(D,E){E=E||{};var C=[D];try{return A(D,E,C,t,o,j,v)}catch(F){throw l(F.error,B,F.line,z.file)}}}var a={};function u(){a={}}function e(y,x){x=x||{};if(x.cache!==false){if(!a[y]){a[y]=q(y,x)}return a[y]}return q(y,x)}function v(z,x,y){return e(z)(x,y)}})(Mustache);

//jQote2 (10/21/2010)
(function($){var _=false,E1="UndefinedTemplateError",E2="TemplateCompilationError",E3="TemplateExecutionError",A="[object Array]",S="[object String]",F="[object Function]",n=1,c="%",q=/^[^<]*(<[\w\W]+>)[^>]*$/,ts=Object.prototype.toString;function r(e,x){throw ($.extend(e,x),e)}function dns(f) {var a=[];if(ts.call(f)!==A)return _;for(var i=0,l=f.length;i<l;i++)a[i]=f[i].jqote_id;return a.length?a.sort().join('.').replace(/(\b\d+\b)\.(?:\1(\.|$))+/g,"$1$2"):_}function l(s,t){var f,g=[],t=t||c,x=ts.call(s);if(x===F)return s.jqote_id?[s]:_;if(x!==A)return[$.jqotec(s,t)];if(x===A)for(var i=0,l=s.length;i<l;i++)return g.length?g:_}$.fn.extend({jqote:function(x,y){var x=ts.call(x)===A?x:[x],d="";this.each(function(i){var f=$.jqotec(this,y);for(var j=0;j<x.length;j++)d+=f.call(x[j],i,j,x,f)});return d}});$.each({app:"append",pre:"prepend",sub:"html"},function(x,y){$.fn["jqote"+x]=function(e,d,t){var p,r,s=$.jqote(e,d,t),$$=!q.test(s)?function(s){return $(document.createTextNode(s))}:$;if(!!(p=dns(l(e))))r=new RegExp("(^|\\.)"+p.split(".").join("\\.(.*)?")+"(\\.|$)");return this.each(function(){var z=$$(s);$(this)[y](z);(z[0].nodeType===3?$(this):z).trigger("jqote."+x,[z,r])})}});
$.extend({jqote:function(e,d,t){var s="",t=t||c,f=l(e);if(f===_)r(new Error("Empty or undefined template passed to $.jqote"),{type:E1});d=ts.call(d)!==A?[d]:d;for(var i=0,m=f.length;i<m;i++)for(var j=0;j<d.length;j++)s+=f[i].call(d[j],i,j,d,f[i]);return s},jqotec:function(x,t){var h,e,y,t=t||c,z=ts.call(x);if(z===S&&q.test(x)){e=y=x;if(h=$.jqotecache[x])return h}else{e=z===S||x.nodeType?$(x):x instanceof jQuery?x:null;if(!e[0]||!(y=e[0].innerHTML)&&!(y=e.text()))r(new Error("Empty or undefined template passed to $.jqotec"),{type:E1});if(h=$.jqotecache[$.data(e[0],"jqote_id")])return h}var s="",i,a=y.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]/g,"").split("<"+t).join(t+">\x1b").split(t+">");for(var m=0,k=a.length;m<k;m++)s+=a[m].charAt(0)!=="\x1b"?"out+='"+a[m].replace(/(\\|["'])/g,"\\$1")+"'":(a[m].charAt(1)==="="?";out+=("+a[m].substr(2)+");":(a[m].charAt(1)==="!"?";out+=$.jqotenc(("+a[m].substr(2)+"));":";"+a[m].substr(1)));s="try{"+('var out="";'+s+";return out;").split("out+='';").join("").split('var out="";out+=').join("var out=")+'}catch(e){e.type="'+E3+'";e.args=arguments;e.template=arguments.callee.toString();throw e;}';try{var f=new Function("i, j, data, fn",s)}catch(e){r(e,{type:E2})}i=e instanceof jQuery?$.data(e[0],"jqote_id",n):e;return $.jqotecache[i]=(f.jqote_id=n++,f)},
jqotefn:function(e){var t=ts.call(e),i=t===S&&q.test(e)?e:$.data($(e)[0],"jqote_id");return $.jqotecache[i]||_},jqotetag:function(s){if(ts.call(s)===S)c=s},jqotenc:function(s){return s.toString().replace(/&(?!\w+;)/g,'&#38;').split('<').join('&#60;').split('>').join('&#62;').split('"').join('&#34;').split("'").join('&#39;')},jqotecache:{}});$.event.special.jqote={add:function(o){var n,h=o.handler,d=!o.data?[]:ts.call(o.data)!==A?[o.data]:o.data;if(!o.namespace)o.namespace="app.pre.sub";if(!d.length||!(n=dns(l(d))))return;o.handler=function(e,m,r){return !r||r.test(n)?h.apply(this,[e,m]):null}}}})(jQuery);

//dot 0.1.7
(function(){var doT={version:"0.1.7"};if(typeof module!=="undefined"&&module.exports){module.exports=doT}else{this.doT=doT}doT.templateSettings={evaluate:/\{\{([\s\S]+?)\}\}/g,interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,conditionalStart:/\{\{\?([\s\S]+?)\}\}/g,conditionalEnd:/\{\{\?\}\}/g,varname:"it",strip:true,append:true};function resolveDefs(c,block,def){return((typeof block==="string")?block:block.toString()).replace(c.define,function(match,code,assign,value){if(code.indexOf("def.")===0){code=code.substring(4)}if(!(code in def)){if(assign===":"){def[code]=value}else{eval("def[code]="+value)}}return""}).replace(c.use,function(match,code){var v=eval(code);return v?resolveDefs(c,v,def):v})}doT.template=function(tmpl,c,def){c=c||doT.templateSettings;var cstart=c.append?"'+(":"';out+=(",cend=c.append?")+'":");out+='";var str=(c.use||c.define)?resolveDefs(c,tmpl,def||{}):tmpl;str=("var out='"+((c.strip)?str.replace(/\s*<!\[CDATA\[\s*|\s*\]\]>\s*|[\r\n\t]|(\/\*[\s\S]*?\*\/)/g,""):str).replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(c.interpolate,function(match,code){return cstart+code.replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g," ")+cend}).replace(c.encode,function(match,code){return cstart+code.replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g," ")+").toString().replace(/&(?!\\w+;)/g, '&#38;').split('<').join('&#60;').split('>').join('&#62;').split('\"').join('&#34;').split(\"'\").join('&#39;').split('/').join('&#47;'"+cend}).replace(c.conditionalEnd,function(match,expression){return"';}out+='"}).replace(c.conditionalStart,function(match,expression){var code="if("+expression+"){";return"';"+code.replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g," ")+"out+='"}).replace(c.evaluate,function(match,code){return"';"+code.replace(/\\'/g,"'").replace(/\\\\/g,"\\").replace(/[\r\t\n]/g," ")+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").split("out+='';").join("").split("var out='';out+=").join("var out=");try{return new Function(c.varname,str)}catch(e){if(typeof console!=="undefined"){console.log("Could not create a template function: "+str)}throw e}};doT.compile=function(tmpl,def){return doT.template(tmpl,null,def)}}());

//Haml (July 16 2011)
var Haml;(function(){var matchers,self_close_tags,embedder,forceXML,escaperName,escapeHtmlByDefault;function html_escape(text){return(text+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/\"/g,"&quot;")}function render_attribs(attribs){var key,value,result=[];for(key in attribs){if(key!=="_content"&&attribs.hasOwnProperty(key)){switch(attribs[key]){case"undefined":case"false":case"null":case'""':break;default:try{value=JSON.parse("["+attribs[key]+"]")[0];if(value===true){value=key}else{if(typeof value==="string"&&embedder.test(value)){value='" +\n'+parse_interpol(html_escape(value))+' +\n"'}else{value=html_escape(value)}}result.push(" "+key+'=\\"'+value+'\\"')}catch(e){result.push(" "+key+'=\\"" + '+escaperName+"("+attribs[key]+') + "\\"')}}}}return result.join("")}function parse_attribs(line){var attributes={},l=line.length,i,c,count=1,quote=false,skip=false,open,close,joiner,seperator,pair={start:1,middle:null,end:null};if(!(l>0&&(line.charAt(0)==="{"||line.charAt(0)==="("))){return{_content:line[0]===" "?line.substr(1,l):line}}open=line.charAt(0);close=(open==="{")?"}":")";joiner=(open==="{")?":":"=";seperator=(open==="{")?",":" ";function process_pair(){if(typeof pair.start==="number"&&typeof pair.middle==="number"&&typeof pair.end==="number"){var key=line.substr(pair.start,pair.middle-pair.start).trim(),value=line.substr(pair.middle+1,pair.end-pair.middle-1).trim();attributes[key]=value}pair={start:null,middle:null,end:null}}for(i=1;count>0;i+=1){if(i>l){throw"Malformed attribute block"}c=line.charAt(i);if(skip){skip=false}else{if(quote){if(c==="\\"){skip=true}if(c===quote){quote=false}}else{if(c==='"'||c==="'"){quote=c}if(count===1){if(c===joiner){pair.middle=i}if(c===seperator||c===close){pair.end=i;process_pair();if(c===seperator){pair.start=i+1}}}if(c===open||c==="("){count+=1}if(c===close||(count>1&&c===")")){count-=1}}}}attributes._content=line.substr(i,line.length);return attributes}function parse_interpol(value){var items=[],pos=0,next=0,match;while(true){next=value.substr(pos).search(embedder);if(next<0){if(pos<value.length){items.push(JSON.stringify(value.substr(pos)))}break}items.push(JSON.stringify(value.substr(pos,next)));pos+=next;match=value.substr(pos).match(embedder);next=match[0].length;if(next<0){break}if(match[1]==="#"){items.push(escaperName+"("+(match[2]||match[3])+")")}else{items.push(match[2]||match[3])}pos+=next}return items.filter(function(part){return part&&part.length>0}).join(" +\n")}embedder=/([#!])\{([^}]*)\}/;self_close_tags=["meta","img","link","br","hr","input","area","base"];matchers=[{name:"html tags",regexp:/^(\s*)((?:[.#%][a-z_\-][a-z0-9_:\-]*)+)(.*)$/i,process:function(){var line_beginning,tag,classes,ids,attribs,content,whitespaceSpecifier,whitespace={},output;line_beginning=this.matches[2];classes=line_beginning.match(/\.([a-z_\-][a-z0-9_\-]*)/gi);ids=line_beginning.match(/\#([a-z_\-][a-z0-9_\-]*)/gi);tag=line_beginning.match(/\%([a-z_\-][a-z0-9_:\-]*)/gi);tag=tag?tag[0].substr(1,tag[0].length):"div";attribs=this.matches[3];if(attribs){attribs=parse_attribs(attribs);if(attribs._content){var leader0=attribs._content.charAt(0),leader1=attribs._content.charAt(1),leaderLength=0;if(leader0=="<"){leaderLength++;whitespace.inside=true;if(leader1==">"){leaderLength++;whitespace.around=true}}else{if(leader0==">"){leaderLength++;whitespace.around=true;if(leader1=="<"){leaderLength++;whitespace.inside=true}}}attribs._content=attribs._content.substr(leaderLength);this.contents.unshift(attribs._content.trim());delete (attribs._content)}}else{attribs={}}if(classes){classes=classes.map(function(klass){return klass.substr(1,klass.length)}).join(" ");if(attribs["class"]){try{attribs["class"]=JSON.stringify(classes+" "+JSON.parse(attribs["class"]))}catch(e){attribs["class"]=JSON.stringify(classes+" ")+" + "+attribs["class"]}}else{attribs["class"]=JSON.stringify(classes)}}if(ids){ids=ids.map(function(id){return id.substr(1,id.length)}).join(" ");if(attribs.id){attribs.id=JSON.stringify(ids+" ")+attribs.id}else{attribs.id=JSON.stringify(ids)}}attribs=render_attribs(attribs);content=this.render_contents();if(content==='""'){content=""}if(whitespace.inside){if(content.length==0){content='"  "'}else{try{content='" '+JSON.parse(content)+' "'}catch(e){content='" "+\n'+content+'+\n" "'}}}if(forceXML?content.length>0:self_close_tags.indexOf(tag)==-1){output='"<'+tag+attribs+'>"'+(content.length>0?" + \n"+content:"")+' + \n"</'+tag+'>"'}else{output='"<'+tag+attribs+' />"'}if(whitespace.around){output='" '+output.substr(1,output.length-2)+' "'}return output}},{name:"each loop",regexp:/^(\s*)(?::for|:each)\s+(?:([a-z_][a-z_\-]*),\s*)?([a-z_][a-z_\-]*)\s+in\s+(.*)(\s*)$/i,process:function(){var ivar=this.matches[2]||"__key__",vvar=this.matches[3],avar=this.matches[4],rvar="__result__";if(this.matches[5]){this.contents.unshift(this.matches[5])}return"(function () { var "+rvar+" = [], "+ivar+", "+vvar+"; for ("+ivar+" in "+avar+") { if ("+avar+".hasOwnProperty("+ivar+")) { "+vvar+" = "+avar+"["+ivar+"]; "+rvar+".push(\n"+(this.render_contents()||"''")+"\n); } } return "+rvar+'.join(""); }).call(this)'}},{name:"if",regexp:/^(\s*):if\s+(.*)\s*$/i,process:function(){var condition=this.matches[2];return"(function () { if ("+condition+") { return (\n"+(this.render_contents()||"")+'\n);} else { return ""; } }).call(this)'}},{name:"silent-comments",regexp:/^(\s*)-#\s*(.*)\s*$/i,process:function(){return'""'}},{name:"silent-comments",regexp:/^(\s*)\/\s*(.*)\s*$/i,process:function(){this.contents.unshift(this.matches[2]);return'"<!--'+this.contents.join("\\n")+'-->"'}},{name:"rawjs",regexp:/^(\s*)-\s*(.*)\s*$/i,process:function(){this.contents.unshift(this.matches[2]);return'"";'+this.contents.join("\n")+"; _$output = _$output "}},{name:"pre",regexp:/^(\s*):pre(\s+(.*)|$)/i,process:function(){this.contents.unshift(this.matches[2]);return'"<pre>"+\n'+JSON.stringify(this.contents.join("\n"))+'+\n"</pre>"'}},{name:"doctype",regexp:/^()!!!(?:\s*(.*))\s*$/,process:function(){var line="";switch((this.matches[2]||"").toLowerCase()){case"":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';break;case"strict":case"1.0":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';break;case"frameset":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">';break;case"5":line="<!DOCTYPE html>";break;case"1.1":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';break;case"basic":line='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">';break;case"mobile":line='<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">';break;case"xml":line="<?xml version='1.0' encoding='utf-8' ?>";break;case"xml iso-8859-1":line="<?xml version='1.0' encoding='iso-8859-1' ?>";break}return JSON.stringify(line+"\n")}},{name:"markdown",regexp:/^(\s*):markdown\s*$/i,process:function(){return parse_interpol(exports.Markdown.encode(this.contents.join("\n")))}},{name:"script",regexp:/^(\s*):(?:java)?script\s*$/,process:function(){return parse_interpol('\n<script type="text/javascript">\n//<![CDATA[\n'+this.contents.join("\n")+"\n//]]>\n<\/script>\n")}},{name:"css",regexp:/^(\s*):css\s*$/,process:function(){return JSON.stringify('<style type="text/css">\n'+this.contents.join("\n")+"\n</style>")}}];function compile(lines){var block=false,output=[];if(typeof lines==="string"){lines=lines.trim().replace(/\n\r|\r/g,"\n").split("\n")}lines.forEach(function(line){var match,found=false;if(block){match=block.check_indent.exec(line);if(match){block.contents.push(match[1]||"");return}else{output.push(block.process());block=false}}matchers.forEach(function(matcher){if(!found){match=matcher.regexp.exec(line);if(match){block={contents:[],indent_level:(match[1]),matches:match,check_indent:new RegExp("^(?:\\s*|"+match[1]+"  (.*))$"),process:matcher.process,render_contents:function(){return compile(this.contents)}};found=true}}});if(!found){output.push(function(){if(line[0]==="\\"){return parse_interpol(line.substr(1,line.length))}function escapedLine(){try{return escaperName+"("+JSON.stringify(JSON.parse(line))+")"}catch(e2){return escaperName+"("+line+")"}}function unescapedLine(){try{return parse_interpol(JSON.parse(line))}catch(e){return line}}if((line.substr(0,2)==="&=")){line=line.substr(2,line.length).trim();return escapedLine()}if((line.substr(0,2)==="!=")){line=line.substr(2,line.length).trim();return unescapedLine()}if((line[0]==="=")){line=line.substr(1,line.length).trim();if(escapeHtmlByDefault){return escapedLine()}else{return unescapedLine()}}return parse_interpol(line)}())}});if(block){output.push(block.process())}var txt=output.filter(function(part){return part&&part.length>0}).join(" +\n");if(txt.length==0){txt='""'}return txt}function optimize(js){var new_js=[],buffer=[],part,end;function flush(){if(buffer.length>0){new_js.push(JSON.stringify(buffer.join(""))+end);buffer=[]}}js.replace(/\n\r|\r/g,"\n").split("\n").forEach(function(line){part=line.match(/^(\".*\")(\s*\+\s*)?$/);if(!part){flush();new_js.push(line);return}end=part[2]||"";part=part[1];try{buffer.push(JSON.parse(part))}catch(e){flush();new_js.push(line)}});flush();return new_js.join("\n")}function render(text,options){options=options||{};text=text||"";var js=compile(text,options);if(options.optimize){js=Haml.optimize(js)}return execute(js,options.context||Haml,options.locals)}function execute(js,self,locals){return(function(){with(locals||{}){try{var _$output;eval("_$output ="+js);return _$output}catch(e){return"\n<pre class='error'>"+html_escape(e.stack)+"</pre>\n"}}}).call(self)}Haml=function Haml(haml,config){if(typeof(config)!="object"){forceXML=config;config={}}var escaper;if(config.customEscape){escaper="";escaperName=config.customEscape}else{escaper=html_escape.toString()+"\n";escaperName="html_escape"}escapeHtmlByDefault=(config.escapeHtmlByDefault||config.escapeHTML||config.escape_html);var js=optimize(compile(haml));var str="with(locals || {}) {\n  try {\n   var _$output="+js+";\n return _$output;  } catch (e) {\n    return \"\\n<pre class='error'>\" + "+escaperName+'(e.stack) + "</pre>\\n";\n  }\n}';try{var f=new Function("locals",escaper+str);return f}catch(e){console.error(str);throw e}};Haml.compile=compile;Haml.optimize=optimize;Haml.render=render;Haml.execute=execute;Haml.html_escape=html_escape}());if(typeof module!=="undefined"){module.exports=Haml};

//blueimp 1.0.2
(function(e){var a=function(b,d){var c=!/[^\-\w]/.test(b)?a.cache[b]=a.cache[b]||a(a.load(b)):new Function(a.arg,("var _s=''"+a.helper+";_s+='"+b.replace(a.regexp,a.func)+"';return _s;").split("_s+='';").join(""));c.tmpl=c.tmpl||a;return d?c(d):c};a.cache={};a.load=function(a){return document.getElementById(a).innerHTML};a.regexp=/(\s+)|('|\\)(?![^%]*%\})|(?:\{%(=|#)(.+?)%\})|(\{%)|(%\})/g;a.func=function(a,d,c,f,g,e,i,h,j){if(d)return h&&h+a.length!==j.length?" ":"";if(c)return"\\"+a;if(f)return"="===
f?"'+_e("+g+")+'":"'+("+g+"||'')+'";if(e)return"';";if(i)return"_s+='"};a.encReg=/[<>&"\x00]/g;a.encMap={"<":"&lt;",">":"&gt;","&":"&amp;",'"':"&quot;","\x00":""};a.encode=function(b){return(""+(b||"")).replace(a.encReg,function(b){return a.encMap[b]})};a.arg="o";a.helper=",_t=arguments.callee.tmpl,_e=_t.encode,print=function(s,e){_s+=e&&(s||'')||_e(s);},include=function(s,d){_s+=_t(s,d);}";"function"===typeof define&&define.amd?define("tmpl",function(){return a}):e.tmpl=a})(this);

/********************************
  PRE-COMPILED TEMPLATES
 ********************************/

// Underscore
window.tpl.underscore = _.template("<div><h1 class='header'><%= header %></h1><h2 class='header2'><%= header2 %></h2><h3 class='header3'><%= header3 %></h3><h4 class='header4'><%= header4 %></h4><h5 class='header5'><%= header5 %></h5><h6 class='header6'><%= header6 %></h6><ul class='list'><% for (var i = 0, l = list.length; i < l; i++) { %><li class='item'><%= list[i] %></li><% } %></ul></div>");

// Mustache
window.tpl.mustache = Mustache.compile("<div><h1 class='header'>{{{header}}}</h1><h2 class='header2'>{{{header2}}}</h2><h3 class='header3'>{{{header3}}}</h3><h4 class='header4'>{{{header4}}}</h4><h5 class='header5'>{{{header5}}}</h5><h6 class='header6'>{{{header6}}}</h6><ul class='list'>{{#list}}<li class='item'>{{{.}}}</li>{{/list}}</ul></div>");

// Handlebars
window.tpl.handlebars = Handlebars.compile("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#each list}}<li class='item'>{{this}}</li>{{/each}}</ul></div>");

// Kendo
window.tpl.kendo = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:true});
 
window.tpl.kendo2 = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:false});

//John Resig's approach
window.tpl.resig = tmpl("<div><h1 class='header'><#= header #></h1><h2 class='header2'><#= header2 #></h2><h3 class='header3'><#= header3 #></h3><h4 class='header4'><#= header4 #></h4><h5 class='header5'><#= header5 #></h5><h6 class='header6'><#= header6 #></h6><ul class='list'><# for (var i = 0, l = list.length; i < l; i++) { #><li class='item'><#= list[i] #></li><# } #></ul></div>");

window.tpl.resig2 = tmpl2("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>");

//jqote2
window.tpl.jqote = $.jqotec("<div><h1 class='header'><%= this.header %></h1><h2 class='header2'><%= this.header2 %></h2><h3 class='header3'><%= this.header3 %></h3><h4 class='header4'><%= this.header4 %></h4><h5 class='header5'><%= this.header5 %></h5><h6 class='header6'><%= this.header6 %></h6><ul class='list'><% for (var n = 0, l = this.list.length; n < l; n++) { %><li class='item'><%= this.list[n] %></li><% } %></ul></div>");

//Dot
window.tpl.dot = doT.template("<div><h1 class='header'>{{= it.header }}</h1><h2 class='header2'>{{= it.header2 }}</h2><h3 class='header3'>{{= it.header3 }}</h3><h4 class='header4'>{{= it.header4 }}</h4><h5 class='header5'>{{= it.header5 }}</h5><h6 class='header6'>{{= it.header6 }}</h6><ul class='list'>{{ for (var i = 0, l = it.list.length; i < l; i++) { }}<li class='item'>{{= it.list[i] }}</li>{{ } }}</ul></div>");

//hogan
window.tpl.hogan = Hogan.compile("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#list}}<li class='item'>{{.}}</li>{{/list}}</ul></div>");

//haml
try {
window.tpl.haml = Haml("%div\n  %h1.header= header\n  %h2.header2= header2\n  %h3.header3= header3\n  %h4.header4= header4\n  %h5.header5= header5\n  %h6.header6= header6\n");
} catch(ex) {
$(".user-output").append("WARNING: HAML could not be compiled on this browser!<br/>");
}

//pure
window.tpl.pure = $p('div.pure').compile({
  h1: 'header',
  h2: 'header2',
  h3: 'header3',
  h4: 'header4',
  h5: 'header5',
  h6: 'header6'
});

//dust
(function(){dust.register("dusttmp",body_0);function body_0(chk,ctx){return chk.write("<h1 class='header'>").reference(ctx.get("header"),ctx,"h").write("</h1><h2 class='header2'>").reference(ctx.get("header2"),ctx,"h").write("</h2><h3 class='header3'>").reference(ctx.get("header3"),ctx,"h").write("</h3><h4 class='header4'>").reference(ctx.get("header4"),ctx,"h").write("</h4><h5 class='header5'>").reference(ctx.get("header5"),ctx,"h").write("</h5><h6 class='header6'>").reference(ctx.get("header6"),ctx,"h").write("</h6>");}return body_0;})();

//blueimp
window.tpl.blueimp = tmpl("<div><h1 class='header'>{%=o.header%}</h1><h2 class='header2'>{%=o.header2%}</h2><h3 class='header3'>{%=o.header3%}</h3><h4 class='header4'>{%=o.header4%}</h4><h5 class='header5'>{%=o.header5%}</h5><h6 class='header6'>{%=o.header6%}</h6></div>");

//eco
window.tpl.eco = eco("<div><h1 class='header'><%- @header %></h1><h2 class='header2'><%- @header2 %></h2><h3 class='header3'><%- @header3 %></h3><h4 class='header4'><%- @header4 %></h4><h5 class='header5'><%- @header5 %></h5><h6 class='header6'><%- @header6 %></h6></div>");

//Ejs
window.tpl.ejs = new EJS({text: "<div><h1 class='header'><%= header %></h1><h2 class='header2'><%= header2 %></h2><h3 class='header3'><%= header3 %></h3><h4 class='header4'><%= header4 %></h4><h5 class='header5'><%= header5 %></h5><h6 class='header6'><%= header6 %></h6></div>"});

//Jade JavaScript output of jade template compiled using node
window.tpl.jadeCmpld=function anonymous(locals,attrs,escape,rethrow){var attrs=jade.attrs,escape=jade.escape,rethrow=jade.rethrow;var buf=[];with(locals||{}){var interp;buf.push("<div><h1");buf.push(attrs({"class":("header")}));buf.push(">");var __val__=header;buf.push(escape(null==__val__?"":__val__));buf.push("</h1><h2");buf.push(attrs({"class":("header2")}));buf.push(">");var __val__=header2;buf.push(escape(null==__val__?"":__val__));buf.push("</h2><h3");buf.push(attrs({"class":("header3")}));buf.push(">");var __val__=header3;buf.push(escape(null==__val__?"":__val__));buf.push("</h3><h4");buf.push(attrs({"class":("header4")}));buf.push(">");var __val__=header4;buf.push(escape(null==__val__?"":__val__));buf.push("</h4><h5");buf.push(attrs({"class":("header5")}));buf.push(">");var __val__=header5;buf.push(escape(null==__val__?"":__val__));buf.push("</h5><h6");buf.push(attrs({"class":("header6")}));buf.push(">");var __val__=header6;buf.push(escape(null==__val__?"":__val__));buf.push("</h6></div><ul>");for(var item in list){buf.push("<li>");var __val__=item;buf.push(escape(null==__val__?"":__val__));buf.push("</li>")}buf.push("</ul>")}return buf.join("")};

//KiTe
window.tpl.kite = kite("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#list}}<li class='item'>{{.}}</li>{{/list}}</ul></div>");

//jsRender

window.tpl.jsRender = $.template(null, "<div><h1>{{=header}}</h1><h2>{{=header2}}</h2><h3>{{=header3}}</h3><h4>{{=header4}}</h4><h5>{{=header5}}</h5><h6>{{=header6}}</h6><ul>{{#each list}}<li>{{=i}}</li>{{/each}}</ul></div>");

// Mote
window.tpl.mote = mote.compile("<div><h1 class='header'>{{{header}}}</h1><h2 class='header2'>{{{header2}}}</h2><h3 class='header3'>{{{header3}}}</h3><h4 class='header4'>{{{header4}}}</h4><h5 class='header5'>{{{header5}}}</h5><h6 class='header6'>{{{header6}}}</h6><ul class='list'>{{#list}}<li class='item'>{{{.}}}</li>{{/list}}</ul></div>");

// Template
window.tpl.template = new Template('<div><h1 class="header"><%= header %></h1><h2 class="header2"><%= header2 %></h2><h3 class="header3"><%= header3 %></h3><h4 class="header4"><%= header4 %></h4><h5 class="header5"><%= header5 %></h5><h6 class="header6"><%= header6 %></h6><ul class="list"><% for (var i = 0, l = list.length; i < l; i++) { %><li class="item"><%= list[i] %></li><% } %></ul></div>');

</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Mustache 0.5.0 DEV (compiled)
tpl.mustache(tpl.vars);
pending…
Kendo UI
tpl.kendo(tpl.vars);
pending…
Kendo UI (no "with" block)
tpl.kendo2(tpl.vars);
pending…
Handlebars
tpl.handlebars(tpl.vars)
pending…
Underscore
tpl.underscore(tpl.vars);
pending…
Resig Micro Templates
tpl.resig(tpl.vars)
pending…
Resig Micro Templates (No "with" block)
tpl.resig2(tpl.vars)
pending…
jqote2 (10/21/2010)
$.jqote(tpl.jqote, tpl.vars);
pending…
dot 0.1.7
tpl.dot(tpl.vars);
pending…
Hogan 1.0.3
tpl.hogan.render(tpl.vars)
pending…
Haml (7/16/11)
//WARNING: Compilation of the template fails in IE7!
tpl.haml(tpl.vars);
pending…
Pure
tpl.pure(tpl.vars);
pending…
Dust
dust.render('dusttmp', tpl.vars, function() {});
pending…
Blueimp 1.0.2
window.tpl.blueimp(tpl.vars);
pending…
eco
tpl.eco(tpl.vars);
pending…
ejs
tpl.ejs.render(tpl.vars);
pending…
Jade
tpl.jadeCmpld(tpl.vars);
pending…
KiTE
tpl.kite(tpl.vars);
pending…
jsRender (jQuery Templates)
tpl.jsRender(tpl.vars);
pending…
Mote
tpl.mote(tpl.vars);
pending…
Template
tpl.template.render(tpl.vars);
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

1 comment

Hack Pass commented :

My relatives always say that I am wasting my time here at web, but I know I am getting familiarity everyday by reading such nice content.

Add a comment