Speaking from the perspective of vNext, we have the following lifecycle hooks/methods currently defined in templating:
These are methods that users can define on their component classes (custom elements and custom attributes), and the framework will invoke them at appropriate times if and only if they are defined:
render, created (during $hydrate)binding, bound (before/after $bind)unbinding, unbound (before/after $unbind)attaching, attached (before/after $attach)detaching, detached (before/after $detach)caching (before $cache)flush (during processFlushQueue, after enqueueFlush)These can be called by users in more advanced situations but in most cases end users will not deal with them directly. I'm listing them here because they're relevant in the bigger picture of avoiding ambiguity:
$hydrate (custom elements/attributes -> initialize component)$bind, $unbind (custom elements/attributes, views -> enqueue hook and mount callbacks)$attach, $detach (custom elements/attributes, views -> enqueue hook and mount callbacks)$mount, $unmount (custom elements, views -> add to DOM)$cache (custom elements/attributes, views)hold, release (views -> set/unset RenderLocation)flush (anything with batching such as observers, resources)patch (bindings -> update targets)connect (AST -> initiate observation)observeProperty (bindings -> called by connect)startObserving (observers -> called indirectly after the first subscribe)We have not named these for the router yet. In vCurrent they are:
canActivate, activatecanDeactivate, deactivateMain candidates for rename are: attach/detach (and pre/post hooks) as well as the router lifecycle hooks.
We're already planning to "get rid of" connect (in the AST) by renaming it to observe (since that's what it does). This also opens up the option of renaming attach to connect.
attach -> connect, keep router hooks as-isThis would be consistent with WebComponents
attaching, $attach, attached to [connecting, $connect, connected]detaching, $detach, detached] to [disconnecting, $disconnect, disconnected]canActivate, activate, canDeactivate, deactivate] as-isattach -> mount, keep router hooks as-isThis moves the ambiguity of attach/activate to the less visible internal api
attaching, $attach, attached] to [mounting, $mount, mounted]detaching, $detach, detached] to [unmounting, $unmount, unmounted]$mount, $unmount] to [$attach, $detach]canActivate, activate, canDeactivate, deactivate] as-isactivate -> entercanActivate, activate] to [canEnter, enter]canDeactivate, deactivate] to [canLeave, leave]activate -> navigateTocanActivate, activate] to [canNavigateTo, navigateTo]canDeactivate, deactivate] to [canNavigateAway, navigateAway]Any other suggestions/variations? Looking for opinions from the community as well as core team members.
most of the confusion for newcomers seem to be that they're confusing the different lifecycles, not an actual naming issue.
i feel like _attached_ describes what it does really well and would prefer to keep it.
i have no strong opinions on renaming activate.
Rename router hooks
activate->navigateTo
- Rename [
canActivate,activate] to [canNavigateTo,navigateTo]- How about
canDeactivateanddeactivate@Alexander-Taran ?
canNavigateAway & navigateAway ?
I'm all for meaningful names.
attached means something to me.
mounted.. means something to me.
connected is somehow abstract.
what does it mean?
is it created?
connected where?
Actually it means rendered. No?
Thanks for this issue, I love bike shedding (not a joke ;-)). Not on this list but I propose changing created to constructed since that better reflects that it happens after the constructor() is called.
Per @Alexander-Taran comment, if attached means rendered then I like rendered but not sure if that is true or not. Although, the recent blog post describes supporting a render method (for JSX) so that naming similarity might cause confusion. No strong opinion here.
Per @gimerstedt comment, the three lifecycles in vCurrent - one for view-model, one for elements, one for routing - really threw me off and even when I learned the difference it was hard to quickly find documentation of the one I wanted. I am glad to see this distinction mostly going away in vNext.
Is there any way to further combine the router and element lifecycles? Two is much better than three, but I would still expect people to get confused when the calls happen relative to one another. For example, when navigating to a route would activate/navigateTo happen before or after attached/mounted/rendered?.
I am really shooting from the hip here but could you combine the router and element lifecycles into one master lifecycle by having the router call canAttach and attached and just past a special argument to those methods so the developer would know the the router called those methods.
I'll try to summarize:
Broadly speaking there are two main lifecycles from a templating perspective: $bind and $attach.
$bind sets up observation and assigns initial values to everything.
$attach adds the actual nodes/elements to the dom so they become visible.
The reverse is $detach and $unbind.
In addition there is a $hydrate lifecycle which is only called once during initialization of a resource (whereas $bind/$unbind and $attach/$detach can be called many times per instance)
A few days ago I made an initial effort on putting this in a sequence diagram but it's hard to decide which details to leave out and such, because some pieces don't mean much without understanding what effects they have. Anyway : https://www.lucidchart.com/publicSegments/view/54a2c1be-6e40-48a3-898c-a7ff815b4bdc/image.png
render() if that hook is present, which passes the job of rendering to the component instead (for custom rendering)created() at the very end, if that hook is present$hydrate is donebinding() if the hook is presentbound() (does not invoke it yet) if the hook is present$bind on its children (bindables and/or child resources) -> bindables will then proceed to update targets (which can be DOM nodes or other bindables) and queues connect (which starts observation)processBoundQueue (only the root initiator will trigger this) indirectly which calls all queued bound()s$bind is doneattaching() if the hook is present$attach on its children$mount on itselfattached() if the hook is presentprocessAttachQueue (only the root initiator will trigger this) indirectly which first calls all $mounts (this actually appends the view nodes to the DOM) and then calls all attached() callbacksThere are a couple details I left out here. There's a little more happening to ensure correct state and such, but this is the gist of it. Then there is the reverse which is very similar ($detach and $unbind)
Thanks @fkleuver , that last post clarifies things nicely.
I'm all for cleaning up the lifecycle hooks. I like @Alexander-Taran's suggestion to rename activate to navigateTo or similar. This is the one lifecycle hook that doesn't seem intuitive on first glance.
Having said that, I think most people understand the difference between the hooks after the first day or so, so don't see it as a huge deal.
My preference is that if it is all possible to rename the hooks in a backward compatible way to avoid breaking existing apps/plugins that'd be great. Perhaps by adding a new hook which delegates to the old one or similar. Hooks are a fairly fundamental concept, and changing them will make a lot of the existing resources (blogs etc) out there invalid.
@freshcutdevelopment We've set ourselves up for some degree of backwards compatibility by prepending all internal lifecycle hooks with the dollar symbol, so the normal bind hook is called $bind, which leaves room for adding a backward-compat hook named bind.
The main issue (if you can call it one) with backwards compat, to give you an example:
If you implement bind() in vCurrent, it replaces the internal lifecycle hook and you have to manually update your bindings. in vNext this is not the case: your own hooks do not replace the internal ones and you never need to manually do something that the framework otherwise would (unless you actually want to, of course, such as with render())
As for attached(), a common thing to do is queueMicroTask when your function needs a fully up-to-date component. With vNext we're already guaranteeing this, so queueing won't be necessary.
This is a recurring pattern. Many advanced scenarios in vCurrent require manually tapping into the task queue or other infrastructure pieces, to ensure the timings are correct. This phenomenon is gone in vNext. Migrating from vCurrent to vNext, from a lifecycle perspective, will mostly involve deleting code.
Hooks are a fairly fundamental concept, and changing them will make a lot of the existing resources (blogs etc) out there invalid.
In vNext actually a lot of things have been greatly simplified for end users (the framework itself does more of the heavy lifting so to speak).
So there will be less things you need to learn. It's going to be easier and require less code to do the same stuff. Old resources will become invalid mostly to the extent that they are simply obsolete.
More new advanced scenarios will be possible that weren't possible in vCurrent and those will require fresh resources anyway. We will be doing our best to invest more in API robustness and documentation to make sure people don't have to rely as much on blogs and such anymore.
So with all that said, I think there's an argument to be made for not throwing aliases in there for the sake of keeping old resources valid. Perhaps to ease migration, but that's all.
As an aside note on the upgrade path, you should seriously make it as painless as possible.
If it's basically a rewrite of my enterprise-level application (such as Angular 1 to Angular 2), where's my incentive to do that? Aurelia is struggling for adoption already, so it won't take much to push existing developers somewhere else. I would welcome 1.x names aliased with 'obsolete method' warnings in the console.
I do agree with @swalters , we are in the same situation with a large business app, ported from a flex one, that is just about to be rolled out. So please consider an easy upgrade path as a major requirement !!!
In the end - and perhaps I haven't made this clear enough in my previous comment - nothing fundamentally changes about the framework. @EisenbergEffect also pointed this out in Q2 report I believe. The syntax and conventions stay the same.
We can address 1. with a v1-compat package that adds various aliases and adapters. vNext can be made to expose the same API as vCurrent. This is possible because vNext can do more than vCurrent, not less.
Point 2. is in itself not a problem because many queueMicroTask calls (which will be added to vNext via a compat layer) are simply not necessary anymore. This doesn't mean that this code will break per se. It just won't be the most optimal code.
The true breaking changes are the other way around. Things will be possible in vNext that aren't possible in vCurrent. It would be a one-way upgrade path once you start tapping into those extra capabilities. But that's reasonable, right?
Obviously, adding a v1-compat package means extra work and testing. It's not realistic to blatantly try and make every nook and cranny of the vCurrent API's work in vNext as well. That would beat the purpose of "vNext".
We need to know which API's (classes, methods, decorators) are most commonly used so we can focus our efforts on making those work (and testing them properly).
Furthermore, we will be spending some time on explaining how to upgrade, what to change. Again, for all but the most advanced scenarios this will likely be an exercise of a few find/replaces, deleting some code and doing some straightforward moving. They would be along the lines of:
bind(bindingContext) to bound() (and use this.scope.bindingContext), and remove your code that updates the values of your bindables (if you don't, that's fine too, its just unnecessary) - we could also add an alias that calls this with bindingContext anywaycompositionTransaction related code and use this.$lifecycle.registerTask(new PromiseTask(somePromise)) instead during bind (though we could surely add an adapter for this)But we'll be looking to reimplement some open source apps in vCurrent with vNext and see how that goes. Then people can take a look and raise any concerns. In the meantime feel free to point out any particular plugins, repos, api's and such that are important to you.
We are not abandoning vCurrent. Don't panic if you've just invested a lot in vCurrent apps. We will keep trying to find common denominators, improve test coverage, automation, reuse CI functionality, and try to backport new features when possible and realistic if the demand is there.
It is of utmost important to us that the transition will be as smooth as possible and if it isn't, then one still wouldn't have to regret creating an app in vCurrent. I am still building apps in vCurrent and so are other core team members. We all have a direct interest in ensuring things keep working.
@swalters @pKrav75 Thanks for weighing in here. This is exactly the type of feedback we want and need. Hopefully, the further explanation from @fkleuver helps to address that. Let us know if you need more information or if you have some specific examples you want to talk through.
The most common purpose and use case for activation is to load data from HTTP and cancel navigation if the data isn't available. The biggest problem with the current naming is that the purpose isn't immediately clear. activate suggests "to turn on", but much of the "turning on" behavior is better captured in attached() (think event handlers) or bind().
In practice, this is harder for developers to learn. A lot of time data loading ends up in non-async callbacks like attached(), which then causes issues with bindings. Likewise when developers see activate(), they don't immediately think "load data," especially if they have no intention of canceling. Finally, the canActivate() method is often the best place for activation, as it allows canceling activation, but activate() fits the mental model of loading data better.
load() loaded() unload() unloaded()?
Most helpful comment
In the end - and perhaps I haven't made this clear enough in my previous comment - nothing fundamentally changes about the framework. @EisenbergEffect also pointed this out in Q2 report I believe. The syntax and conventions stay the same.
Here's the main changes:
Backwards compatibility
We can address 1. with a
v1-compatpackage that adds various aliases and adapters. vNext can be made to expose the same API as vCurrent. This is possible because vNext can do more than vCurrent, not less.Point 2. is in itself not a problem because many
queueMicroTaskcalls (which will be added to vNext via a compat layer) are simply not necessary anymore. This doesn't mean that this code will break per se. It just won't be the most optimal code.The true breaking changes are the other way around. Things will be possible in vNext that aren't possible in vCurrent. It would be a one-way upgrade path once you start tapping into those extra capabilities. But that's reasonable, right?
We need your help to identify important APIs and use cases
Obviously, adding a
v1-compatpackage means extra work and testing. It's not realistic to blatantly try and make every nook and cranny of the vCurrent API's work in vNext as well. That would beat the purpose of "vNext".We need to know which API's (classes, methods, decorators) are most commonly used so we can focus our efforts on making those work (and testing them properly).
Furthermore, we will be spending some time on explaining how to upgrade, what to change. Again, for all but the most advanced scenarios this will likely be an exercise of a few find/replaces, deleting some code and doing some straightforward moving. They would be along the lines of:
bind(bindingContext)tobound()(and usethis.scope.bindingContext), and remove your code that updates the values of your bindables (if you don't, that's fine too, its just unnecessary) - we could also add an alias that calls this with bindingContext anywaycompositionTransactionrelated code and usethis.$lifecycle.registerTask(new PromiseTask(somePromise))instead during bind (though we could surely add an adapter for this)But we'll be looking to reimplement some open source apps in vCurrent with vNext and see how that goes. Then people can take a look and raise any concerns. In the meantime feel free to point out any particular plugins, repos, api's and such that are important to you.
Last but not least..
We are not abandoning vCurrent. Don't panic if you've just invested a lot in vCurrent apps. We will keep trying to find common denominators, improve test coverage, automation, reuse CI functionality, and try to backport new features when possible and realistic if the demand is there.
It is of utmost important to us that the transition will be as smooth as possible and if it isn't, then one still wouldn't have to regret creating an app in vCurrent. I am still building apps in vCurrent and so are other core team members. We all have a direct interest in ensuring things keep working.