Reputation: 542
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?
Upvotes: 28
Views: 19398
Reputation: 730
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
Upvotes: 1
Reputation: 746
You could also use Grunt.js and a handlebars template compiler. I've used the "grunt-ember-templates" plugin and it works well.
https://npmjs.org/package/grunt-ember-templates
Upvotes: 7
Reputation: 1111
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>'),
})
Upvotes: -16
Reputation: 2886
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");
Upvotes: 0
Reputation: 5611
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 templateName
s to template
s 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>
Upvotes: 38
Reputation: 8389
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
Upvotes: 3