ibm-js / delite

HTML Custom Element / Widget infrastructure
http://ibm-js.github.io/delite/
Other
68 stars 28 forks source link

compile templates at build time rather than at run time #432

Closed wkeese closed 9 years ago

wkeese commented 9 years ago

Refactor how handlebars plugin works in builds.

There are a number of enhancements/bug fixes from this refactor relating to builds:

  1. Reduce CPU used at page load time by precompiling templates at build time.
  2. Make sure that dependencies specified in templates via the requires="..." attribute are properly included into the build.
  3. Builds with templates no longer download requirejs-text/text.js, delite/Template.js, and delite/handlebars.js to the browser. That's assuming that you do a custom build (rather than using the delite/layer.js file), and assuming that the builder and loader are working correctly. We could also consider excluding handlebars.js and Template.js from the delite/layer.js file.

Also one bug fix for the non-build case: stop using the text! plugin directly since the parentRequire() method passed to load() runs in the context of the caller. If the caller remapped requirejs-text/text to point to another module, it would inadvertently affect the behavior of delite/handlebars.

Previously, the build step for handlebars!foo.html would merely write this to the layer file:

define("requirejs-text/text!foo.html", function(){
   return "...";
});

Thus the build eliminated the XHR to get the template text, but still ran template compilation at page load, and the browser still needed to download delite/handlebars.js, and therefore also requirejs-text/text.js and delite/Template.js.

With this commit, the handlebars build writes the generated template function to the layer, for example:

define('delite/handlebars!deliteful/list/List/_PageLoaderRenderer.html',["deliteful/ProgressIndicator"], function(){
        return function anonymous(document,register
/**/) {
this.setClassComponent('template', (this.loading ? 'd-loading' : ''), this)
var c1 = this.renderNode = register.createElement('div');
...
return {
        ...
        refresh: function(props){
                if('loading' in props)
                        this.setClassComponent('template', (this.loading ? 'd-loading' : ''), this);
                ...
        }.bind(this),

        destroy: function(){
        ...
        }.bind(this)
};

Note that this increases the bytes needed for each template. For example, deliteful's layer.js goes from 112351 bytes / 26393 gzipped to 127540 bytes / 28103 gzipped. But on the other hand, it means that Template.js doesn't need to be downloaded to the browser, a savings of 9536 bytes (3230 gzipped). You don't currently get that savings though if you include delite/layer.js, since delite/layer.js currently includes Template.js and handlebars.js.

PR in #431.