-
-
Notifications
You must be signed in to change notification settings - Fork 407
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pre-RFC: Deprecate implicit injections (owner.inject) #508
Comments
I am in favor of moving this forward. I and teammates ran into this problem recently from an initializer that indirectly prevented stubbing a service. The indirection, though self-inflicted, caused confusion that could be easily avoided.
By establishing you access dependencies only through explicit injection we simplify the mental model and teaching it. It also paves the way to remove initializers. |
YAAAAS. would part of this RFC also include updating the route/controller/etc blueprints to include things like export default class MyExplicitRoute extends Route {
@service store;
} ? |
TBH, I don't think so. It is very easy to add when you need it, and I don't particularly think that most files will use it (certainly not most controllers, but unsure RE: the breakdown in routes). |
Indeed, though I'd like to be very clear that I'm not specifically proposing that at this time. We might want to do it (I personally would like to), but I haven't thought through all of the possible reasons that folks use initializers/instance-initializers enough to be confident that we can address all use cases in other ways. |
Completely agree. I think focusing the scope of the above change as sharply as we can will make it easier to design and implement successfully. Small steps. |
I’m in favor. This is a pretty strong requirement for making static services be a thing in embroider. |
The "how we teach this" section should be pretty straightforward - add injecting the store into examples in the Guides and API docs. I think we may have already started doing this in some places. Also there is one section here to be updated. |
I said it in the meeting today: I think there are (imo) pretty high value in not having to repeat the same thing all over the place, so I think it's important to also consider moving to having an app-level super class so that these kind of things can have a proper home. |
I like the idea of an app-level base class. Living in the app makes it more search-discoverable by app authors, when compared with imperative injections inside addon code. |
@chancancode so you're thinking there would be something like I'd be 👍 for that since it gives a nice inheritance to follow (for humans and tools) while reducing duplication and showing off how to extend common functionality. |
Explicitness would make it easier to teach. Otherwise, it can provide a frustrating experience for newbies.
|
I'm also very much in favor of this (and the future 🔥 sacrifice of initializers)! Is RE: base class or injections via blueprint, I appreciate the Rails approach of commented code as hints in blueprints. Something like this: $ ember g controller foo
$ cat app/controllers/foo.js
import Controller from '@ember/controller';
export default FooController extends Controller {
# make sure ember-data is installed and uncomment the next line to get access to the Data Store.
# @service store
} I personally don't have a problem with having to repeat the injections everywhere. It shouldn't be too difficult to write an initializer to re-inject in all controllers and routes if that's really what is needed. |
Yes, |
I have no specific objection to this idea, but I really don't want to couple that design with removing implicit injections. |
👋
I can help here if we want to start this work pre 4.0! |
Sounds good! |
I'm defining "implicit injections" as the type of injection where nothing exists in the class body (or inherited from the parent class), but a property is magically present anyways. These types of implicit injects are nearly always done from initializers or instance-initializers (both of which should also die in a 🔥, but that is another issue). Examples of these implicit injections are using this.store from within an arbitrary
Route
/Service
/Controller
/Component
without first specifyingstore: injectService()
.Implicit injections have long been a source of confusion for new comers and old-timers alike.
Since the advent of
Ember.inject.service
(from waaaaayyy back in Ember 1.9.0!) we have had a much better way to bring in external collaborating services like this. Explicit injections are massively easier to reason about since you can easily see that the class itself (or its ancestor) defines the injection.As mentioned above the most used implicit injection is
this.store
(though there are others) which might indicate that this is "Ember Data's problem", but due to the nature of these implicit injections there is really no way thatember-data
can actually deprecate usage of these implicit injections. Ifember-data
removes the initializer that sets up the implicit injections, it is clearly a breaking change.ember-data
has no way to ensure that thestore
property emits a deprecation (but only if not "clobbered" bystore: injectService()
) which means that it can't even be removed in a major version bump due to Ember's unique SemVer commitment (to not remove any undeprecated public APIs in a major version bump).We must provide a mechanism to deprecate these implicit injections wholesale. They are bad, they make our programs harder to understand, 🔥🔥🔥.
Concrete implementation suggestion:
owner.inject
that allows the caller to specify that the injection is deprecated, which version it is deprecated until, a deprecationid
, and aurl
for reading more about the deprecation. (For those of you following along, I've just described theoptions
argument to@ember/debug
'sdeprecate
method 😉)owner.inject
is not provided that new extra "deprecations" object.The goal of this pre-RFC is:
The text was updated successfully, but these errors were encountered: