
Stop sending template engines to the browser. How to make 6-10x faster templates - adambrault
http://andyet.net/blog/2012/sep/13/stop-sending-template-engines-to-the-browser-a-ret/
======
dmix
Dust.js [1] has precompile templates and LinkedIn showed how much faster it is
than iCanHaz [2].

[1] <http://akdubya.github.com/dustjs/>

[2] [http://engineering.linkedin.com/frontend/client-side-
templat...](http://engineering.linkedin.com/frontend/client-side-templating-
throwdown-mustache-handlebars-dustjs-and-more)

~~~
HenrikJoreteg
dust looks neat, for sure.

------
ahoge
>Thinking about this leaves me asking: why don't we just send the javascript
template function to the client instead of doing all the template
parsing/compiling on the client?

You can do this with Handlebars. I use a Grunt task to pre-compile all
templates and then I just bundle them with the much smaller (it adds about 1kb
or so) "vm" version of Handlebars.

Locally, I use the full version of Handlebars and regular non-compiled
templates.

~~~
nfriedly
Same here. I had some trouble with partials until I realized that you can just
compile everything as a template and then do

    
    
        Handlebars.partials = Handlebars.templates
    

:)

~~~
ahoge
I use:

    
    
        Handlebars.registerPartial("Foo", Handlebars.templates.Foo);
    

Your approach is kinda amazing. Makes me wonder why not all templates are
automatically available as partial by default. Are there cases where you
wouldn't want that?

~~~
nfriedly
I think the reason is Handlebars is supposed to look and act like Mustache and
templates aren't named in Mustache, so they don't get named in "regular"
Handlebars:

    
    
        var getHtml = Handlebars.compile("<div>yad yada...</div>");
    

And then following the rule of least surprise, if templates aren't partials
during normal usage, then they shouldn't be with precompilation.

At least that's my guess. I didn't figure out my trick until digging through
the source to figure out what was different. (Not much - just how/where
they're stored & referenced.)

~~~
ahoge
Ahm... yea, I forgot that I put them into `Handlebars.templates` myself if
they aren't there yet (i.e. during development).

------
drblast
Does anyone going through all this this know how to manipulate the DOM
directly? It's ridiculously simple.

The whole approach strikes me as odd, unless I'm missing something.

~~~
Tichy
Don't know the current state, but for a while it was a lot faster to just
replace the HTML source (innerHTML I think?) than to manipulate the DOM. Just
the way the browsers were implemented. No idea if the situation has improved
by now.

~~~
drblast
Either way, it looks to me like this approach has to manipulate HTML strings
to find a {{tag}} like that. Which seems like it's a lot more work than this:

<div id='thingToReplaceWithData1234"></div>

and then adding a child text node or such to that element. Whether you do that
via InnerHTML or CreateTextNode doesn't matter, either seems faster and easier
to me than doing a string substitution.

But I don't know, I never really got the appeal of the framework of the week.
If it helps write decent web sites, then I guess that's good, but I've noticed
that simple sites now are ridiculously slow and I'm guessing this is the
reason.

~~~
Tichy
It seems faster, but unfortunately it isn't (or wasn't). That's just the
thing. When I started, I also thought using DOM was a no-brainer, but there
are all those tiny speed optimizations people make...

------
latchkey
This posting seems like basic knowledge, but I can see how people get lazy and
don't do this step as part of their build process and just send things to the
browser to do it for them.

Part of the issue is that the default bin/handlebars script doesn't really
support walking a tree and outputting a directory structure with all of the
precompiled templates, but I've got my own hacked version of it which does...

<https://gist.github.com/3719225>

    
    
      handlebars ./handlebars --min --outputDir ./js/tmpl
    

I also have a build script setup in Eclipse so that when I save the file, it
automatically builds things... (similar to this)...

[http://stackoverflow.com/questions/6645640/integrating-
coffe...](http://stackoverflow.com/questions/6645640/integrating-coffeescript-
with-eclipse/7507987#7507987)

I use requirejs with a paths configuration like this:

    
    
      handlebars: 'handlebars.runtime-1.0.0.beta.6'
    

This allows me to just write this in my CoffeeScript for each page on my
site...

    
    
      require('handlebars')
      require('tmpl/org/requests')
      ...
      
      requests.html(Handlebars.templates.org_requests(requests: requests)
    

All of this works amazingly well and has really allowed me to segment my code
and templates up into little sections for reusability. Also, no need for ever
loading the compiler part of handlebars in the client even during development.

~~~
HenrikJoreteg
Judging by the response, it appears to not be basic knowledge. But, I'm glad
to hear that you and others are taking a similar approach as I think it just
makes a lot more sense as a concept.

~~~
latchkey
Sorry, I meant the part about the requirement to precompile templates in order
to have the fastest possible experience.

~~~
davedx
It's common sense once someone explains it to you, but when you're learning
about all of this new client-side tech you tend not to worry about speed until
later, and then it's useful to see posts like these telling you what you can
do.

I guess this is why frameworks like Rails compile your assets for you - it's a
"silly not to do it" task, but not everyone knows about it.

~~~
latchkey
Right on the homepage of handlebarsjs.com...

"It is also possible to precompile your templates. This will result in a
smaller required runtime library and significant savings from not having to
compile the template in the browser. This can be especially important when
working with mobile devices."

But nobody reads documentation... ;-)

------
bemmu
Am I missing something on why you can't just include your "templates" as
display:none snippets of HTML and then .clone() them from the DOM and change
the fields as needed? Perhaps my needs just haven't been complex enough to
need a JS templating engine.

~~~
sisk
From an accessibility standpoint, this is a bad idea. Not that long ago, you
had to make considerations for clients without CSS support (e.g., text-based
browsers or screen readers). Across the board, things have gotten
significantly better but there is still the issue of a stylesheet not loading
(and mixing markup and CSS isn't great so that shouldn't be considered a
reasonable alternative).

If a renderer comes across a script tag it doesn't know how to parse (e.g., a
script of type `text/template`), it doesn't do anything with it, however it
remains the responsibility of the markup renderer and, therefore, you're not
relying on something else (CSS or JavaScript) to hide it.

~~~
ricardobeat
Not really, if you add style="display:none" inline, or use the `hidden`
attribute, it will be correctly ignored by all screen readers.

<script type="whatever"> is mostly used because it's completely ignored. It's
safely hidden, difficult to be accidentally messed with, and doesn't take
parsing/rendering time from the browser.

~~~
sisk
Right but, as mentioned, inline styling is mixing markup and styles so it's
best avoided (plus you're still relying on CSS to hide the content).

Regarding the `hidden` attribute, there is no support for it in IE (at least
up to and including 9).

~~~
sopooneo
I know a lot of people argue against mixing markup and styling. As one of
those, and since you seem well informed, how do you feel about the various css
frameworks like bootstrap where the class names are essentially style
descriptions?

------
seiji
Hulk Hogan generates JS functions from your templates too:
<https://github.com/twitter/hogan.js/blob/master/bin/hulk>

You should probably never be parsing templates on the client.

~~~
grejdi
We use RhinoJS to compile our Mustache templates with Hogan, since we don't
have a NodeJS environment to compile this in.

~~~
grejdi
I put together this gist as a quick how-to: <https://gist.github.com/3719753>

------
tsahyt
I remember a time when template engines ran on the server and sent finished
HTML pages to the clients. What happened to that and why have we adopted
methods such as this? Is this to balance load away from the server?

~~~
TazeTSchnitzel
Well, as someone who has seemingly missed the client-side MVC revolution, I
still use server-side templating. And it's great, especially over slow
conections. And it degrades gracefully when JS support is unavailable.

~~~
tsahyt
> when JS support is unavailable

That, yes. I noticed that my CPU load was noticeably high browsing some sites.
Nothin special, just news sites. I found that quite annoying so I activated
NoScript, suddenly the load was gone. The problem is, that NoScript seems to
"deactivate" half of the web for me these days, precisely because of client-
side templating.

There've been some valid reasons stated here though. However, the site I'm
working on uses server-side templating, that's why I was asking in the first
place.

------
nostrademons
Closure templates does this. It's never occurred to me that someone would do
it any other way.

------
julius
The Google Closure javascript framework precompiles templates, too.
<https://developers.google.com/closure/templates/>

------
dochtman
I've written a Jinja-to-JavaScript compiler:

<https://bitbucket.org/djc/jasinja>

It reuses the Jinja front-end, it really only replaces Jinja's code generator
and supports a pretty large subset of Jinja. I think this is particularly
great because it allows you to switch from server-side template rendering to
client-side rendering of templates piecemeal, or use both with the same
templating language.

~~~
masklinn
That's kinda neat. I assume it only supports built-in filters and control
structures?

~~~
dochtman
The compiler output looks roughly like this:

    
    
      var Jasinja = {
        "filters": {
          "attr": function(obj, name) { return obj[name]; }
        },
        "tests": {
          "lower": function(val) { return val.toLowerCase() == val; }
        },
        "templates": {
          "test": {
            "macros": {},
            "blocks": {},
            "render": function(ctx, tmpl) {
              return "a";
            }
          }
        }
      };
    

So you can easily add some filters by setting Jasinja.filters['myfilter'] to a
function.

------
andybak
So. Write your templates in your server-side templating language. That way you
can serve full html for initial page loads and compiled-to-javascript versions
to allow Ajax updates.

Something like this: [https://github.com/comolongo/Yz-Javascript-Django-
Template-C...](https://github.com/comolongo/Yz-Javascript-Django-Template-
Compiler)

~~~
andybak
Thinking about this some more and here's me clarifying things for myself...

There's basically 4 strategies:

1\. Give the client a full html page

2\. Give the client pre-rendered html snippets

3\. Give the client javascript that can render html and replace values without
having to do much computation

4\. Make the client do the template rendering probably using a library such as
mustache.

So...

1\. Should be the default and the fallback for dumb devices such as spiders
and old browsers

2\. Is ideal if the page doesn't change much - typical content heavy sites.
You have to have proper urls and history management though.

3\. is optimal for "it's an app not a website"

4\. is only OK if you know your clients have plenty of CPU to spare. So not
mobile basically...

------
philfreo
I use Grunt (<http://gruntjs.com>) to compile them for production.

    
    
            handlebars: {
                compile: {
                    options: {
                        namespace: "JST"
                    },
                    files: {
                        "dist/debug/templates.js": ["templates/**/*.hbs"]
                    }
                }
            },
    

Then you can concat templates.js with the rest of your JS and your template
functions are ready to go!

<https://npmjs.org/package/grunt-contrib-handlebars>

~~~
latchkey
For a multiple page website, it seems like it is a waste to serve up all of
the templates for the entire site. I try to serve the template that is
specific for the page.

------
ricardobeat
I'd be really happy if someone would contribute template compiler adapters for
Flour[1]. It's pretty straight-forward.

<https://github.com/ricardobeat/cake-flour/>

------
dreamdu5t
You can have HTML linebreaks in JavaScript and HTML literals!

<https://github.com/laverdet/js-xml-literal> :)

~~~
HenrikJoreteg
That's a pretty awesome hack.

------
jakejake
Are these template pre-compiled by the server at runtime or is there a build
process before deploying the app to the server?

If it was happening at run-time, I'd probably rather just have the client do
the compiling instead of the server. Since the client isn't going to notice a
few extra milliseconds, but on the server that can add up under high load.

------
jpk
SoundCloud also precompiles their Handlebars templates. In general, it seems
like a good idea.

[http://backstage.soundcloud.com/2012/06/building-the-next-
so...](http://backstage.soundcloud.com/2012/06/building-the-next-soundcloud/)

------
yesbabyyes
This is a great way to do client side templating. I use Sam Stevenson's stitch
and eco templates to do this, so I can require a template whenever it's
needed.

------
aymeric
Is there similar solution in the .NET world? I am using Knockout.js with
underscore templates, and I would like to give this technique a try.

~~~
jerf
It's a technique in a lot of worlds:
<http://en.wikipedia.org/wiki/Partial_evaluation>

(BTW, I just mean this as informative. I wish more people were aware of this
idea, and I wish more mainstream languages would make this easier.)

------
bbrizzi
Any idea on how client-side templating affects search engine referencing? Do
crawlers always execute the javascript?

------
kylemathews
I use Brunch.io to do this. It precompiles all my templates and adds them to
my app.js file.

------
georgedyer
Anyone have thoughts on using coffeekup?

------
zbychuk
I am sorry, maybe I am missing something important, but what is a logical
difference between what you propose and concepts like ASP, PHP, ASP.NET? I am
using templates in all pages, but only because data is known only on a client,
i.e. I get data from AJAX call and fill-in a template (jsrender, knockout,
others)

~~~
charliesome
People have this belief that server side templates are slow.

~~~
drivebyacct2
Is this said in good faith? There are lots of reasons for client side
templates, but I rarely (never) see anyone citing it because rendering on the
server is slower than rendering on the client.

~~~
sirclueless
Client-side rendering probably isn't faster than server-side rendering in
terms of latency, but it is cheaper. You save on server processing and network
bandwidth.

Rendering speed isn't the reason server-side templates feel "slow" though: if
you do server-side rendering then every change of state on the client needs to
round-trip to the server in order to fetch a new HTML representation. Client-
side rendering lets you "cheat": just render the new state and synchronize
with the server after the fact.

~~~
drivebyacct2
Right.

------
rorrr
He's missing the point of client-side templates.

~~~
HenrikJoreteg
care to elaborate?

~~~
dabarnes
I think what he means is that its pre-compiled on the server, but is
forgetting that is it client side templating because you are inflating your
templates with data and adding them into the dom in the client as opposed to
doing it on the server. pre-compiled doesn't mean server side.

