Upgrade to 1.10.0-beta lessons

Continuing the discussion from HTMLBars in 1.10.0-beta.4 - template must be a function:

Ok, so to summarize from my previous post:

  • “Legacy” ember app, no ember-cli, bower, require.js, common.js.
  • Build process based on grunt-ember-templates
  • Handlebars templates precompiled on the server and served with handlebars-runtime
  • Manual update, without the easy ember-cli based option.

Here are the lessons.

  • You no longer need an EmberEnv switch to enable HTMLBars. There was a short lived bug that had produced some misleading google results.

  • grunt-ember-templates that is on npm ATM doesn’t support what is needed to make this work, but their master on git has the needed fixes. I believe this will be fixed shortly.

  • There is no replacement for handlebars and/or handlebars-runtime js files you needed to link in manually. Htmlbars is now baked into ember.

  • There’s an ember-template-compiler project on git. However the version there is 2 months old (last stable) and doesn’t support HTMLBars. That led me on the wrong path of believing I needed to utilize…

  • HTMLBars project on github. I actually hacked together a grunt task using this raw compiler and it actually worked… until I tried using the “{#each}” helper.

    I spent a good few hours digging through the output of both github-derived and baked-in htmlbars compiler. Here’s what it comes down to:

    • template: {#each breadcrumb in breadcrumbs}

    • output from the github master compiler: block(env, morph2, context, "each", [get(env, context, "breadcrumb"), get(env, context, "in"), get(env, context, "breadcrumbs")], {}, child0, null);

    • output from the baked-in compiler: block(env, morph0, context, "each", [get(env, context, "breadcrumbs")], {"keyword": "breadcrumb"}, child0, null);

    So, either “native” handlebars doesn’t support #each helper, or one of the versions is out of date. Either way, that led me back to…

  • This pull request, where @rwjblue actually provided all the hints I needed to make this work. The trick is that the correct ember-template-compiler version is now hosted on bower. Raw files can be found here: GitHub - components/ember: Shim repository for the Ember Application Framework. It is recommended to download both ember and ember-template-compiler from there, so versions would be synced.

  • Once the basic HTMLBars started working, other stuff started breaking. Namely, all the old handlebars helpers. There’s supposedly a compatibility layer, but if you’re doing anything more ambitious, you’re better off rewriting them into htmlbars helpers.

  • Rewriting a helper into htmlbars comes down to changing all the Ember.Handlebars.registerHelper() calls into Ember.HTMLBars.registerHelper(). And then changing the method signature, which now takes 4 arguments:

    • params: array with the ordered arguments. All the stuff that used to be before options
    • hash: what used to be at options.hash, only simplified
    • options: the old options, stripped down of a few things
    • env: I think this is the old buffer/context that used to be in options, didn’t touch it
  • There are no longer contexts and types info for the values in params and hash (ever since the 1.9 actually). Everything is now either a literal string or a stream (which you should check for). I still have no idea how to manipulate these streams, but it seems setting up ValueBinding still produces bound property, and that was good enough for my use case.

  • If you are calling any built-in helper you need to call helper.helperFunction instead of just helper. Example: return Ember.HTMLBars.helpers.view.helperFunction.call(this, [App.MyView], hash, options, env);

That’s it so far. Speed increase feels about 50%, although I’m yet to run more elaborate tests.

Note: I suspect that most of this could have been prevented by finding the right articles or forum posts where this stuff is explained. However, if such things do exist, Google was unable to find them.

2 Likes

I believe Ember has always differed from “native” handlebars (and I assume by extension htmlbars) by providing it’s own helpers and extensions that hook things up the Ember Way in order that computed properties and so on work correctly.

http://emberjs.com/api/classes/Ember.Handlebars.helpers.html

Please correct me if I’m wrong, I’m still building on my knowledge of Ember internals!

Hmm, seems native handlebars has #each helper, but only uses {{#each items}} syntax. No mention of {{#each item in items}} style syntax on their site.

Yes, Ember has it’s own {{#each}} implementation - Ember - 4.6 - Ember API Documentation

1 Like

Correct. HTMLBars compiler is baked into debug versions of Ember (ember.js and ember.debug.js), but will not be included in production versions (ember.prod.js). If you need to precompile assets with a production version of Ember, you will have to also load ember-template-compiler.js into your app (essentially replacing loading handlebars.js).

The ember-template-compiler is now paired with the version of Ember you are using. Both ember.prod.js and ember-template-compiler.js are published (to S3 and Bower) in tandem. The ember-template-compiler NPM package will likely be released to support 1.10.0, but contain information on it being deprecated (in favor of using the specific version for each Ember release).

This should not be true, please open a bug report with details at Issues · emberjs/ember.js · GitHub. Helpers that previously worked should absolutely continue to work.

Directly calling helpers from within other helpers is not really supported. While it may work, it is certainly not part of Ember’s public API and is something to be avoided.

Agreed. I am sorry that the information was not readily available, and thank you for taking the time to write up your findings.

Since I already have a grunt pipeline, I’m doing my own minimization instead of using ember.prod.js. Still, good to know.

I was doing stuff like manipulate options.fn, options.hashTypes, options.hashContexts… Before 1.9, even more than that. Also, injecting my own hacks using grunt. So, not exactly a proper usage.

I suspect plain, interface-respecting helpers will work just fine. Except the next part.

Official or not, the idiom is certainly widespread enough you should put out some kind of warning in the upgrade docs.

ember.prod.js is not minified, it contains a number of performance improvements over using ember.debug.js (as much as 15% faster). To make this more obvious to folks, we have renamed the generated ember.js file to ember.debug.js.

This is absolutely not a public API, and any usage of it has no guarantee to work across versions. In most cases today, these sorts of helpers should be rewritten as components (which can easily invoke other helpers via their layout).

We have no documentation that suggest using helpers that call helpers, and as such I don’t really think that we should document that you shouldn’t do it either (we don’t document the things not to do).

1 Like

There’s some confusion surrounding the name change, I was actually already using prod for minimization. Either way, I’ll update the build config to include the ember-templates, thx.

Ok, fair enough.

I wished I bumped in to this earlier it could saved me at least 4 hours… As of Ember 1.11.1, Ember.HTMLBars.helpers.view.helperFunction.call(this, [App.MyView], hash, options, env); is no longer valid Ember.HTMLBars.helpers returns undefined still trying to figure out how to fix ember easyForm helpers e.g Ember.Handlebars.helpers.view.call(this, Ember.EasyForm.Error, options);

I ended up using this:

Ember.HTMLBars._registerHelper("my-view", function (params, hash, options, env) {
	//...

	return Ember.Handlebars.helpers.view.helperFunction.call(this, [MyView], hash, options, env);
});

… for now.

after digging through ember source code we can : return env.helpers.view.helperFunction.call(this, [viewClass], hash, options, env);

_registerHelper is currently private so kinda unsafe to use but not sure if we have any other options… https://github.com/emberjs/ember.js/pull/10379