I'm enjoying emberjs a lot and would like to take the next step in a couple of my small, mobile apps and precompile my Ember/Handlebars templates as part of my build process.
I'd prefer to stay away from messing with Ruby and would like to use node.js as I'm more comfortable with using it.
I believe what I want to use is Ember.Handlebars.precompile, but unfortunately I'm unable to load the canonical ember.js file in a node environment. Example of a naive attempt from the node repl:
> var e = require('./ember');
ReferenceError: window is not defined
at /Users/jeremyosborne/git/projects/ldls/client/lib/emberjs/src/ember.js:5:1
at Object.<anonymous> (/Users/jeremyosborne/git/projects/ldls/client/lib/emberjs/src/ember.js:1596:2)
--- stack trace, you get the idea ---
I think I've already figured out how to set them up in my code so that they work correctly with my views, I just want to compile them in an environment outside of a browser DOM.
In lieu of getting the canonical ember.js to load in node, are there a specific set of files that I can pluck from the ember repo and use to compile my templates?
EDIT
I did a kluge fix that works great but gets an F for maintainability. I grabbed all the Handlebars
code minus the reference to the window
object. Then I followed with the Ember.Handlebars.Compiler
code, replacing Ember.create
with Object.create
, exporting my Ember
object, and viola things work seemingly great in node (as in it works and the functions produced are templates). But I don't consider this an answer to my own question due to the aforementioned maintainafail, so still open for answers.
EDIT 2
The above turns out to be a total fail. Perhaps there's something wrong in the procedure, but using Ember.Handlebars.precompile
or Ember.Handlebars.compile
doesn't work. The templates get made, but when I use the precompiled templates attached to Ember.TEMPLATES in my code, they do not work. I only seem to be able to get templates to work when they are explicitly passed in the modified script tags, as suggested on the emberjs.com site.
EDIT 3 I figured out what I was doing wrong. My answer is below.
Look at the code for the official ember-rails gem at https://github.com/emberjs/ember-rails
While it's not a node.js project, it does show you how to precompile the templates using the Rails 3.1+ asset pipeline, and it includes all the necessary Javascript code that you would need to do it in Node without having to hack together a solution that you'd have to maintain on your own.
More specifically, look at vendor/assets/javascripts/ember-precompiler.js and lib/ember-rails/hjs_template.rb
I'm far from an expert on Node (obviously, Rails is more my thing).. but I think those two files should point you in the right direction. Basically, you're going to want to concatenate ember-precompiler.js (which acts as a "shim" for lack of a better word) with ember.js and then call EmberRails.precompile to compile your templates.
I've written a grunt plugin called grunt-ember-handlebars that does exactly this. It pretty much mimics Garth's script, with one important difference:
It uses lib/headless-ember.js and lib/ember.js, which are maintained (at least for now) by ember.js to precompile default templates. If you don't want to use grunt, you can extract the relevant code from the precompile_handlebars helper in tasks/ember-handlebars.js.
Take a look at the npm package Ember-Runner
window object can be mocked by jsdom
and now you can run anything from Ember including
Ember.Handlebars.compile
I wrote an official precompiler npm module for anyone else who might be wanting to do this w/ a recent version of ember.js
https://npmjs.org/package/ember-template-compiler
It's simple to install and use (example below)
npm install ember-template-compiler
Found a good enough solution to my problem that seems easy enough to maintain that I'll consider my problem solved.
Here's how I solved things:
window.Handlebars = Handlebars;
and remove it.Ember.create
and change toObject.create
.var Ember = require('./my_ember_precompiler').Ember
.var templateString = Ember.Handlebars.precompile(str).toString()
.Handlebars.template()
and make sure this wrapped function is added to theEmber.TEMPLATES
object.The above is painless when it's automated in a script.