-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Conversation
name: "clock", | ||
|
||
initialize: function(instance) { | ||
var clock = instance.container.lookup("clock:main"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doing a lookup in a container will likely break things, especially when introducing 3rd party add-ons. Can we not advertise this footgun approach? We likely need to add some construct to solve the pain of removing this, but it is important we do.
We have discussed this at at least 2 F2F meetings, documenting it seems like a poor idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the footgun you are concerned about? A brief search of GitHub (https://github.com/search?utf8=%E2%9C%93&q=initializer+container.lookup&type=Code&ref=searchresults) shows many, many uses of container.lookup()
in initializers.
We need to give people a transition path right now (this is a deprecation guide, not regular documentation). Do you think we should hold off on incremental changes until a solution that eliminates container.lookup
in initializers entirely is in place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the footgun you are concerned about?
A brief search of GitHub (https://github.com/search?utf8=%E2%9C%93&q=initializer+container.lookup&type=Code&ref=searchresults) shows many,
that search is extremely scary, for example each occurrence of lookup('store:main')
(their are many) in that search fails to specific its initializer ordering dependency as after ember-data, which means it is entirely luck, that their application boots. Any change to the initializer dep graph can result in a topology change that may result in a broken app.
This isn't just hypothetical, i have witnessed this in the wild an unfortunate amount of times.
So, this means eager instantiating during initializers destabilizes application boot.
An example: 2 independent initializers that both appear reasonable, do not work together.
Please note, the most problematic cases are when these initializers exist in add-ons, but the issue still remains without add-ons.
// initializer1.js
container.inject('router:main', 'km', 'service:kiss-metrics')
container.lookup('router:main').on('didtransition', function() { this.km.track(..) });
// initializer2.js
container.inject('router:main', 'google', 'service:google-analtyics')
container.lookup('router:main').on('didtransition', function() { this.google.track(..) });
Depending on the initialization order, either google analytics or kiss metrics will be broken. Why, because the the eager lookup, proceeds the injection rule of the later initializer.
proposed solution.
// initializer1.js
container.inject('router:main', 'km', 'service:kiss-metrics')
container.onLookup('router:main', function(router) {
router.on('didTransition', function() { this.km.track(..) })
});
// initializer2.js
container.inject('router:main', 'google', 'service:google-analtyics')
container.onLookup('router:main', function(router) {
router.on('didTransition', function() { this.google.track(..) })
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to give people a transition path right now (this is a deprecation guide, not regular documentation). Do you think we should hold off on incremental changes until a solution that eliminates container.lookup in initializers entirely is in place?
Guiding people down a path that is fundamentally broken and uses private API seems irresponsible. The above mentioned API should be a reasonably quick addition and then this deprecation entry can merely suggest the correct path forward.
@stefanpenner Thanks so much for clarifying the specific issue you are worried about. This exact kind of problem was, indeed, a motivator for the API that I initially designed with Dan in December, talked about with the core team, and have finally implemented here. To be concrete: the problem is that it is important for all app-wide injection rules to be set up before any instances are created through the container. In the new design, which this deprecation guide is helping people transition to, Indeed, the deprecation warning that caused a user to find this web page is catching the precise bug you are worried about. That is because the Can you see any ways in which the new system would still exhibit the bug you are worried about. |
@wycats ah I see, my mistake the instanceInitializer is post initialization curious, why not have |
#### Deprecate Access to Instances in Initializers | ||
|
||
Previously, initializers had access to an object that allowed them to | ||
both registry new classes and get instances of those classes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/registry/register
@stefanpenner I was worried that people would refactor initializers that look like this: App.initializer({
name: 'foo',
initialize: function(container) {
container.lookup('foo:bar');
}
}); into: App.instanceInitializer({
name: 'foo',
initialize: function(container) {
container.lookup('foo:bar');
}
}); But |
@jgwhite Fixed, thanks! |
@wycats I disagree with you a little bit here. I think the case you're highlighting is valid, but in practice I believe it sacrifices long-term ergonomics over hypothetical, short-term confusion. We have made changes in the past where the objects passed to hooks have changed, but their most popular methods remained to help in migration, and it has not caused mass bedlam yet. My feeling is that, instead of passing the registry/container, and the potential for access to all sorts of private things, we instead pass the Application/ApplicationInstance, and add methods that proxy to the public methods of the registry and container, respectively. |
@tomdale I disagree with you here, but I think we can let it simmer. |
How me and @wycats have technical discussions. |
Here is my attempt to thread this needle: I consider the I agree with @tomdale that we can transition to passing the We already expose the registry's Similarly, we can also expose the container's Here are some more benefits to the proxy approach:
|
@dgeb Thank you Dan, that is a thorough articulation of what I'd like to see happen. |
Needs a rebase... |
The docs for the initializer deprecation http://emberjs.com/deprecations/v1.x/#toc_deprecate-access-to-instances-in-initializers could really use an ES6 module exports example in the code snippet. The initializer blueprint doesn't produce code that looks like that, so it's a little tricky to figure out (read: I don't get it). Here's one that came up in the latest Ember Weekend podcast that is covered by this deprecation, I think: https://gist.github.com/code0100fun/f9b99b2a562702683602#file-app_initializers_session-js |
@tomdale - Needs a rebase... |
Instance initializers deprecation
Adds a deprecation guide for the deprecations introduced by instance initializers. Should be merged with emberjs/ember.js#10256.