28

My Emberjs app is running slowly so I wanted to precompile my template to ease the runtime a bit. However I'm lost on how to proceed. I read http://handlebarsjs.com/precompilation.html and Emberjs introduction but no, all I could do was just creating a template file as instructed on the site, and I cannot figure out what and how to do with this template file in Emberjs.

How can I precompile templates in Emberjs? What should I do with the template file to use it in Emberjs?

bmeurant
  • 3,277
  • 1
  • 16
  • 14
Stargazer
  • 542
  • 1
  • 4
  • 8
  • 1
    If you are using `gulp` I recently published a package to npm called [gulp-ember-templates](https://www.npmjs.org/package/gulp-ember-templates) which will compile your handlebars templates into javascript and then you can concat them into a single file – Stuart May 29 '14 at 19:23
  • possible duplicate of [Easy way to precompile Emberjs Handlebar templates with nodejs?](http://stackoverflow.com/questions/9171583/easy-way-to-precompile-emberjs-handlebar-templates-with-nodejs) – givanse Jul 09 '14 at 22:48

6 Answers6

38

To clarify, Thomas' example as-written is still doing the template compilation at run-time. I think his point, though, was that after you've loaded your precompiled Ember-Handlebars templates you can do this:

MyApp.MyView = Ember.View.extend({
  template: Ember.TEMPLATES.mytemplate,
})

The problem with using Handlebars' built-in precompiler is that Ember's Handlebars implementation adds some functionality on top of what Handlebars itself provides, so you'll want to install the ember-precompile package, which provides basically the same interface as the handlebars command-line utility, but using Ember's Handlebars implementation.

This will avoid you having to change all your templateNames to templates and having to add in the Ember.TEMPLATES... in each view, since it automatically updates Ember's built-in template cache.

So, assuming you've already loaded your pre-complied templates.js file as output from ember-precompile templates/*.handlebars -f templates/templates.js, here's a more complete example snippet of a worker import/initialization order:

<script src="/lib/handlebars-1.0.0.beta.6.js"></script>
<script src="/lib/ember-1.0.pre.js"></script>
<script src="/lib/ember-data-latest.js"></script>
<script>
  var App = Ember.Application.create();
</script>
<script src="/templates/templates.js"></script>
<script src="/js/models.js"></script>
<script src="/js/views.js"></script>
<script src="/js/controllers.js"></script>
<script src="/js/router.js"></script>
<script>
  App.initialize();
</script>
Gabriel Grant
  • 5,415
  • 2
  • 32
  • 40
  • 1
    I think your examples are showing vanilla handlebars compilation. I was under the impression that Ember.Handlebars should be used to precompile templates. – Luke Melia Sep 15 '12 at 03:57
  • 1
    @LukeMelia you're totally right, that wasn't very clear -- I'd called the ember-precompile script "handlebars" on my machine, which is really confusing. It's now `ember-precompile`, and installable via NPM :) – Gabriel Grant Sep 15 '12 at 06:10
  • I found out the hard way that my compiled templates were using "Handlebars.helpers" instead of "Ember.Handlebar.helpers". And so, most of the common ember helpers - view, partial, outlet, etc, weren't available, and it was driving me crazy. Thanks! – Shiprack Mar 01 '13 at 04:08
  • Got excited this would work, too soon. I'm not getting this error "Template was precompiled with an older version of Handlebars than the current runtime. Please update your precompiler to a newer version (>= 1.0.0-rc.3) or downgrade your runtime to an older version (<= 1.0.rc.2)" – Shiprack Mar 01 '13 at 04:15
  • But then I found this, which works like a charm: https://npmjs.org/package/ember-tools#ember-generate---scaffold-resource – Shiprack Mar 01 '13 at 04:35
7

You could also use Grunt.js and a handlebars template compiler. I've used the "grunt-ember-templates" plugin and it works well.

http://gruntjs.com/

https://npmjs.org/package/grunt-ember-templates

okor
  • 666
  • 8
  • 13
3

Here is a gist showing how to precompile handlebars templates and add the result to the Ember.TEMPLATES object, which Ember consults to resolve named templates.

https://gist.github.com/2013669

Luke Melia
  • 8,389
  • 33
  • 41
1

I'm using Gulp for builds, and precompiling templates looks like this:

var handlebars = require('gulp-ember-handlebars');
var concat = require('gulp-concat');

var SRC = {
    TEMPLATES: ['app/templates/**/*.{hbs,html}']
};

gulp.task('templates', function() {
  return gulp.src(SRC.TEMPLATES)
    .pipe(handlebars({outputType: 'browser'}))
    .pipe(concat('templates.js'))
    .pipe(gulp.dest(DEST.SCRIPTS));
});

Then I use the Handlebars runtime library rather than the full version.

Ember-Handlebars: https://www.npmjs.org/package/gulp-ember-handlebars

Rahul_Dabhi
  • 709
  • 8
  • 30
0

You can precompile in the client's browser, as Thomas Bartelmess stated.

You can also precompile using handlebars via nodejs (taken from my very own Jakefile):

var Handlebars = require('handlebars');
precompile = (function () {
    //Lovingly extracted from Ember's sources.
    var objectCreate = Object.create || function (parent) {
            function F() {}
            F.prototype = parent;
            return new F();
        },
        Compiler = function () {},
        JavaScriptCompiler = function () {};

    Compiler.prototype = objectCreate(Handlebars.Compiler.prototype);
    Compiler.prototype.compiler = Compiler;
    JavaScriptCompiler.prototype = objectCreate(Handlebars.JavaScriptCompiler.prototype);
    JavaScriptCompiler.prototype.compiler = JavaScriptCompiler;
    JavaScriptCompiler.prototype.namespace = "Ember.Handlebars";
    JavaScriptCompiler.prototype.initializeBuffer = function () {
        return "''";
    };
    JavaScriptCompiler.prototype.appendToBuffer = function (string) {
        return "data.buffer.push(" + string + ");";
    };
    Compiler.prototype.mustache = function (mustache) {
        if (mustache.params.length || mustache.hash) {
            return Handlebars.Compiler.prototype.mustache.call(this, mustache);
        } else {
            var id = new Handlebars.AST.IdNode(['_triageMustache']);
            if (!mustache.escaped) {
                mustache.hash = mustache.hash || new Handlebars.AST.HashNode([]);
                mustache.hash.pairs.push(["unescaped", new Handlebars.AST.StringNode("true")]);
            }
            mustache = new Handlebars.AST.MustacheNode([id].concat([mustache.id]), mustache.hash, !mustache.escaped);
            return Handlebars.Compiler.prototype.mustache.call(this, mustache);
        }
    };
    return function precompile(string) {
        var ast = Handlebars.parse(string);
        var options = {
            knownHelpers : {
                action : true,
                unbound : true,
                bindAttr : true,
                template : true,
                view : true,
                _triageMustache : true
            },
            data : true,
            stringParams : true
        };

        var environment = new Compiler().compile(ast, options);
        return new JavaScriptCompiler().compile(environment, options, undefined, true);
    };
}());

strPrecompiledTemplate = item.handlebarsTemplateFolders.map(function (dir) {
    console.info("\tProcessing " + dir);
    return readdirRecursiveSync(dir).map(function (file) {
        console.info("\t\t" + file);
        var content = fs.readFileSync(file, 'utf-8');
        content = Handlebars.precompile(content);
        file = file.replace(/\.[^\.]+$/, '').replace(/^src\//g, '').substr(dir.length).replace(/^\/+/, '');
        // Pay attention: The wrap in Ember.Handlebars.template() is important!
        return "Ember.TEMPLATES['"+file+"'] = Ember.Handlebars.template("+content+");";
    }).join("\r\n");
}).join("\r\n");
Fordi
  • 2,798
  • 25
  • 20
-16

You can set the precompiled handlebars output to the template property (not templateName) on you ember view. This is what ember also does under the hood

MyApp.MyView = Ember.View.extend({
  templateName: "myViewWhatever",
  template: Ember.Handlebars.compile('<p>{{blah}}</p>'),
})
Community
  • 1
  • 1
Thomas Bartelmess
  • 1,111
  • 8
  • 17