Anyone Upgrading to 1.0?

Is there anyone out there who’s running an app on Ember 0.9.x and wants to upgrade to 1.0 (any version)? Would you like to swap tips? Would you be interested in a library that helps you make the transition?

Our app runs on 0.9.8.1 with CP_DEFAULT_CACHEABLE and VIEW_PRESERVES_CONTEXT both set to false.

CP_DEFAULT_CACHEABLE

We have been fairly successful with the following technique for upgrading CP_DEFAULT_CACHEABLE:

  1. set CP_DEFAULT_CACHEABLE to false (0.9.7.1 compatibility)
  2. create a “style test”-- a Ruby test (but any language would do) that does static analysis against our codebase. It Looks for calls to .property() that lack a subsequent .cacheable() or volatile() call. At this point, the style test doesn’t run in the CI environment
  3. run the test and find all violations
    1. if there are very few, fix them in a single PR and enable the style test in CI
    2. if there are many, fix a few in a single PR, then go back to (3) when that is merged
  4. wait some time to make sure you’ve worked all the kinks out
  5. set CP_DEFAULT_CACHEABLE to true (1.0) compatibility
  6. wait some more time
  7. remove the test and calls to .cacheable()

I’m not sure static analysis is the best answer here. It might have been better to monkey-patch Ember.ComputedProperty to emit errors or warnings (depending on the environment) if it’s using the default cacheability behavior. If I do write a library, I’ll likely do this.

VIEW_PRESERVES_CONTEXT

We have been less successful with upgrading all our views and templates to 1.0-compatibility. Our first attempt was to

Em.View.reopen({
  view: function() { return this; }.property().cacheable()
})

That would let us change {{foo}} to {{view.foo}} in any template where foo is a property on the view’s context. The problem is that there’s no static analysis that could tell us how much progress we’ve made. We scrapped that and created a mixin:

Em.Mixin.create({
  _preservesContext: !!Ember.VIEW_PRESERVES_CONTEXT,
  _templateContext: Em.computed(function(property, value) {
    if (arguments.length > 1) {
      return value;
    }
    if (this.get('_preservesContext')) {
      var parentView = get(this, '_parentView');
      if (parentView) { return get(parentView, '_templateContext'); }
    }
    return this;
  }).cacheable()
});

This lets us set whether views preserve context on a class-by-class basis. It’s still not possible to do static analysis (since there’s no easy way to determine whether a class is a subclass of Em.View statically), but we can do runtime analysis. We simply iterate over all classes (recursively from App.*) and check whether they’re Em.View subclasses; if so, we fail if they don’t preserve context.

One trick we use here is grandfathering in existing code. We want to stop the bleeding by forcing people to set _preservesContext: true on all new views. Then, we can whittle down the list of grandfathered view classes over time. Once it gets to 0, we remove the mixin and the text and set VIEW_PRESERVES_CONTEXT to true globally.

We’re not there yet, so I don’t know how well that will go.

/cc @stefan.penner

@jamesarosen thanks for sharing this! I’ll probably have to port an old ember app soon,

I still have to start, so far it seems that the biggest chunk of work for me will be to refactor a lot of the logic that I now have in the old StateMachine based router…

I would be really interested if you want to share your scripts!

I can definitely talk about how we’re transitioning from Ember.StateMachine to the router. I think the lessons there won’t be quite as generally useful since there was no common starting point. That is, every Ember 0.9 app had to make up routing on its own. We, for example, use Sammy to map URLs to states.

I’ll add a post here about that transition shortly.

1 Like