-
Notifications
You must be signed in to change notification settings - Fork 604
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
Use without mixins #1619
Comments
I agree we should try and move away from mixins at some point. |
The big advantage of mixins is that they make incorporating ESA's into apps very easy. Of course @mike-north's approach above works well but especially for mixins that add multiple methods (and properties) that's tedious and error-prone. We should investigate closely what options we have for dropping mixins without making integrating ESA much harder than it is today. Just thinking out loud here but what if we just switched to classes? import AuthenticatedRoute from 'ember-simple-auth/routes/authenticated'
export default class extends AuthenticatedRoute {
} There are likely other alternatives… |
One possible way, as well just thinking out loud, could be to wrap Route class with custom creation function, for more cleaner user's class and simple integration, for instance: import { createAuthenticatedRoute } from 'ember-simple-auth/routes/authenticated'
class ApplicationRoute extends Route {}
export default createAuthenticatedRoute(ApplicationRoute, { /* optional config */ }); |
I think we can find a way that is no more difficult, but possibly more explicit (a good thing imo) than just adding (mystery) mixins in several places. Let's aim for easiest to understand and maintain, and fight the temptation to optimize for smallest # of lines. Something like this is easy for developers to understand, and they're free to use inheritance for their own needs instead of extending from some base class import { redirectIfUnauthenticated } from 'ember-simple-auth/authenticated-route'
class HomeRoute extends Route {
beforeModel(transition) {
super.beforeModel(transition);
redirectIfUnauthenticated(transition, 'auth.login');
}
} Or the decorator approach import { authenticatedRoute } from 'ember-simple-auth/authenticated-route'
@authenticatedRoute
class HomeRoute extends Route {
} I would like to caution against something like this -- it's essentially an "ES6 mixin", and has even more pitfalls than ember mixins // ember-simple-auth/authenticated-route.js
export function authenticatedRoute(baseRouteClass) {
return baseRouteClass extends {
beforeModel() { .... }
}
}
// app/routes/home.js
import Route from '@ember/routing/route';
import { authenticatedRoute } from 'ember-simple-auth/authenticated-route.js';
export default class extends authenticatedRoute(Route) {
} To be clear, my hope is that all this can be accomplished through a little clever refactoring, without disturbing the existing mixin-oriented public API. |
Totally agree. I'm not worried about number of lines but the amount of complexity we'd be putting on the dev's shoulders if instead of just mixing in one mixin in the right class, they'd have to do lots of wiring themselves. The problem with the first approach above: import { redirectIfUnauthenticated } from 'ember-simple-auth/authenticated-route'
class HomeRoute extends Route {
beforeModel(transition) {
super.beforeModel(transition);
redirectIfUnauthenticated(transition, 'auth.login');
}
} is that while being relatively easy (and explicit) for the I'm not 100% convinced switching to classes would lead to a lot of pain in reality actually. I understand, forcing people to extend another class than Lastly, I'm not sure whether there's some sort of mechanism that's establishing in JS outside of Ember that could replace mixins? I guess that would likely be // ember-simple-auth/authenticated-route.js
export function authenticatedRoute(baseRouteClass) {
return baseRouteClass extends {
beforeModel() { .... }
}
}
// app/routes/home.js
import Route from '@ember/routing/route';
import { authenticatedRoute } from 'ember-simple-auth/authenticated-route.js';
export default class extends authenticatedRoute(Route) {
} although the So long story short, if we could make the first approach work without it becoming too complex, I'd totally be in favor of that as it's probably "the right thing to do" anyway but I'm not sure that's easily possible… |
Looks like there's already a mixin-free approach for which makes sense since there's not much need for it to be tightly coupled with a route. It just needs to:
Come to think of it, the number of reasons why The initializer approach commented above is 💯, particularly if the router was used for Looking at
Great abstractions show just enough information about the problem being solved (and how it's being solved) that you can have an idea of how it works -- mixins often expose almost no information about what they do or how they do it. As such, I'd caution against looking for "another way to mixin". Many teams who have been plagued by mixin-related pain have undertaken efforts (at LinkedIn this is called "Project: Mixout", at Yahoo it was called I'd be happy to put my money where my mouth is, and take a stab at some of this myself (the codebase for this addon is so refined and well-documented that it doesn't seem like a big job), with the promise of keeping the public API surface intact. A good start would be
at which point, we'll see where the true points of coupling are between Mixin and Thing-That-Is-Mixed-Into |
I'd be interested in helping out with this issue. |
I think the main reason (besides there being no Route.extend(ApplicationRouteMixin, {
invalidationSucceeded() {
// do my custom thing here
this._super(...arguments); // make sure all of ESA runs
}
}); I think maintaining an easy way for extending ESA's out of the box functionality is important when we look at new solutions. I'm looking forward to what you'll come up with @mike-north! The plan you laid out above looks 💯 |
I personally would like to see a decorator approach. I think it makes it explicit and easy to reason about. |
Since Ember is moving to native classes it would be interesting to hear the current status of this issue 🙂 I also think that a decorator approach would fit better to modern Ember. |
@tschoartschi - class decorators have some of the same pitfalls as mixins, and with the decorator spec in flux, there's significant risk and maintenance overhead around using decorators for things like this. I'd like to see a flexible "regular function API" as the means for consuming ember-simple-auth in an ember octane app. |
@mike-north thanks for the reply :-) so, for now, we would need to do something like: import ApplicationRouteMixin from 'ember-simple-auth/mixins/application-route-mixin';
export default class ApplicationRoute extends Route.extend(ApplicationRouteMixin, {}) {
} Or are there better solutions? |
See the top post in this thread for a "regular function API" example. Mixins and decorators are both abstractions that hide very important details from consumers. |
@mike-north it's not totally clear to me if this is a solution which already works and should be used (and is supported by the maintainers of |
The exact example I cited is a goal, not something that currently exists. Some things are possible already w/ no mixin use (i.e., #1619 (comment)) Once we have more of this new part of this initiative fleshed out the plan is to unveil and support a new (additional) portion of the public API that allows for consumption w/o mixins. |
@mike-north for arguments sake, all a decorator is is a function that wraps another function, so technically, it would still be a functional API. ;) |
For now we just use the solution I outlined here: #1619 (comment) it works fine also together with TypeScript but nevertheless, it would be nice to see the same APIs across the whole ember ecosystem. |
What is the status of this? Are there any plans to move this forward and remove mixins from the programming model? Ember Octane is approaching fast, and it would be super helpful not to need mixins anymore. Also, there is a Pre-RFC to deprecate mixins: emberjs/rfcs#534. |
This will require a bunch of work. We're currently focussing on getting a 2.0 release out which would allow us to remove a bunch of cruft. Once that's done, we can focus on future initiatives again like this one. |
Has there been any progress on this now that 2.1 has been out for a while? |
I've updated today my in-development app to ember-source 3.17.3 (from ember-source 3.17.1) and I've received a linter error |
I confirm the linter error with package eslint-plugin-ember v8, not error in v7 |
Quick update for everyone: There is currently no way to use ESA without mixins and thus that linter error. You'll have to disable that warning wherever you use the mixins that ESA comes with. We are working on a decorators-based version of ESA and will release that soon (🤞). Until then continue using the mixins as described in the docs – there are no immediate negative consequences of that. |
Thanks Marco! |
mixins are deprecated now – see #2198 |
Is there a plan for allowing consumption of ember-simple-auth in a codebase that bans or restricts use of mixins? Examples include a codebase making use of ES6 classes and/or TypeScript, where mixins are largely unsupported (and will be for the foreseeable future)
One ultra-low-effort solution to this problem might be to expose the functions on the object passed to
Mixin.create( )
forApplicationRouteMixin
,AuthenticatedRouteMixin
, etc... for direct consumption.The text was updated successfully, but these errors were encountered: