7 ms·
Stop sending template engines to the browser. How to make 6-10x faster templates
- ahoge 14y ago>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 14y agoSame 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 14y agoI 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 14y agoI 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 14y agoAhm... yea, I forgot that I put them into `Handlebars.templates` myself if they aren't there yet (i.e. during development).
- HenrikJoreteg 14y agoPerhaps I should have been a bit more specific. I don't really care so much about how you do it whether it's with jade or handlebars + grunt or whatnot (I happen to like jade). The main point is that pre-compiling and sending JS functions instead of strings is way faster and makes more sense.
- bemmu 14y agoAm 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.
- fla 14y agoWondering the same here. And what about caching the template library?
- lincolnq 14y agoI use a JS templating engine (Handlebars with compiled templates). When you have 3- or 4-level nested templates with 50+ fields to fill in, it's much easier to write (and especially to maintain) the snippets of HTML with {{name}}-type template tags, rather than writing the code to query the DOM and replace elements as needed. Especially if you have a designer who's comfortable manipulating HTML elements but allergic to JavaScript.
- MatthewPhillips 14y ago50 fields in a single template??? I use the parents technique because it punishes you for making gloat decisions like that.
- sisk 14y agoFrom 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.
- 14y ago
- dreamdu5t 14y agoYou can have HTML linebreaks in JavaScript and HTML literals! https://github.com/laverdet/js-xml-literal https://github.com/laverdet/js-xml-literal :)
- jorgem 14y agothat's cool.
- HenrikJoreteg 14y agoThat's a pretty awesome hack.
- zbychuk 14y agoI 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 14y agoPeople have this belief that server side templates are slow.
- kevincennis 14y agoFor certain applications, they are. If I have a single page web app, I don't want the overhead of returning markup. I just want JSON. And when I get raw data back instead of a string of HTML, I can be a lot smarter about responding to user input (e.g. optimistic updates).
- ahoge 14y agoWell, you send something to the server, then the templating happens, and then it's sent back to you. Even indefinitely fast templating would be slow due to network latency. Also, sending JSON back and forth is kinda nice because it's fairly compact, easy to handle on both sides, and additionally this particular API may be used for other purposes, too.
- drivebyacct2 14y agoIs 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 14y agoClient-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.
- ricardobeat 14y agoI'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/ https://github.com/ricardobeat/cake-flour/
- aymeric 14y agoIs 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 14y agoIt's a technique in a lot of worlds: http://en.wikipedia.org/wiki/Partial_evaluation 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.)
- HenrikJoreteg 14y agoYou can just pre-process them with node and then use the generated template functions in whatever app you want. It's just client-side JS at that point. This isn't unlike pre-process SASS, or SCSS, etc.
- dmix 14y agoDust.js [1] has precompile templates and LinkedIn showed how much faster it is than iCanHaz [2]. [1] http://akdubya.github.com/dustjs/ http://akdubya.github.com/dustjs/ [2] http://engineering.linkedin.com/frontend/client-side-templating-throwdown-mustache-handlebars-dustjs-and-more http://engineering.linkedin.com/frontend/client-side-templat...
- HenrikJoreteg 14y agodust looks neat, for sure.
- latchkey 14y agoThis 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 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-coffeescript-with-eclipse/7507987#7507987 http://stackoverflow.com/questions/6645640/integrating-coffe... 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 14y agoJudging 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 14y agoSorry, I meant the part about the requirement to precompile templates in order to have the fastest possible experience.
- davedx 14y agoIt'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.
- seiji 14y agoHulk Hogan generates JS functions from your templates too: https://github.com/twitter/hogan.js/blob/master/bin/hulk https://github.com/twitter/hogan.js/blob/master/bin/hulk You should probably never be parsing templates on the client.
- philfreo 14y agoI use Grunt (http://gruntjs.com 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 https://npmjs.org/package/grunt-contrib-handlebars
- latchkey 14y agoFor 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.
- kylemathews 14y agoI use Brunch.io to do this. It precompiles all my templates and adds them to my app.js file.
- drblast 14y agoDoes 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.
- Osiris 14y agoYou are missing something. My team uses Handlebars templates with Ember.js. We build templates with placeholders for bound values or other view templates. When rendered on the client side, a change to a data model causes an automatic change in any templates that are bound to that data. In jQuery there's a potential for forgetting to write code to update a value or part of the page. With this templating system, it's all bound and auto-updated. Another reason that we use templates is that we put all the template files up on a CDN. The only thing our server serves up is an empty DOM (just a body and a div), and the templates are all built into the DOM on the client side. Lastly, managing a bunch of small tmpl files with the HTML we want is a lot easier than trying to embed HTML into JavaScript strings to use with jQuery. We just write up some HTML and an Ember view that renders that template in the right place on the page. Organizationally it's very simple and easy to maintain.
- jacobr 14y agoDirect DOM manipulation does not mean that you render things server side and then manipulate them. It also does not mean that you embed HTML in JavaScript strings. The difference is whether you use the DOM APIs (with or without jQuery) to create and update elements, or template libraries and innerHTML.
- dmix 14y agoThis is impractical with any JS-heavy application; where you are working primarily with javascript data structures and not the DOM. It also leads to jQuery spaghetti code. So many people use jquery like a shotgun, to solve every JS problem, when better - and more targeted - solutions can be tailored out of small modular libraries.
- gliese1337 14y ago
- rorrr 14y agoHe's missing the point of client-side templates.
- HenrikJoreteg 14y agocare to elaborate?
- dabarnes 14y agoI 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.
- jpk 14y agoSoundCloud also precompiles their Handlebars templates. In general, it seems like a good idea. http://backstage.soundcloud.com/2012/06/building-the-next-soundcloud/ http://backstage.soundcloud.com/2012/06/building-the-next-so...
- yesbabyyes 14y agoThis 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.
- jakejake 14y agoAre 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.
- dochtman 14y agoI've written a Jinja-to-JavaScript compiler: https://bitbucket.org/djc/jasinja 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 14y agoThat's kinda neat. I assume it only supports built-in filters and control structures?
- dochtman 14y agoThe 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.
- tsahyt 14y agoI 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 14y agoWell, 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 14y ago> 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.
- davedx 14y agoWe've moved the entire MVC + routing frameworks all into the client in one go. Now it seems we're experimenting with which bits of work can still be delegated to the server. Pretty interesting times really, it all still feels very experimental. As someone just learning Backbone.js this stuff fascinates me :)
- anonymouz 14y agoOr we're just on the next iteration of the endless thin client -> fat client -> thin client -> fat client -> ... trend change. Now with 100% more bloat.
- adrianhoward 14y ago1) Yes to balance the load and to save bandwidth (if you have the same engine on front and back end you can make that decision late in the process or change your mind and move stuff between the front and back end depending on how the performance comes out) 2) These days more work just happens on the front end. With some web apps the back end is a pure data store and all the GUI is rendered on the front end. Doing a round trip for each front-end change would make the UI to unresponsive to be useful.
- julius 14y agoThe Google Closure javascript framework precompiles templates, too. https://developers.google.com/closure/templates/ https://developers.google.com/closure/templates/
- nostrademons 14y agoClosure templates does this. It's never occurred to me that someone would do it any other way.
- bbrizzi 14y agoAny idea on how client-side templating affects search engine referencing? Do crawlers always execute the javascript?
- georgedyer 14y agoAnyone have thoughts on using coffeekup?
- andybak 14y agoSo. 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-Compiler https://github.com/comolongo/Yz-Javascript-Django-Template-C...
- andybak 14y agoIt would be nice to add a layer on top of this that did partial page updates, managed the json views and the history push-state too. It might be possible to have code where you just transparently wrote normal server-side views and the framework intelligently decided whether to render on the server or client and handled all the plumbing for you.
- andybak 14y agoThinking 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...