-
Notifications
You must be signed in to change notification settings - Fork 396
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
refactor(engine-core): Simplify unmount process #2709
Conversation
vm.children = EmptyArray; | ||
|
||
runChildNodesDisconnectedCallback(vm); | ||
vm.velements = EmptyArray; |
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.
Love seeing so much red! ❤️
c251502
to
c367c5e
Compare
c367c5e
to
7961d7c
Compare
packages/integration-karma/test/rendering/disconnect-order/index.spec.js
Outdated
Show resolved
Hide resolved
0861b56
to
4627b82
Compare
This PR raised some questions about lifecycle callback invocation timings, the difference between native and synthetic shadow DOM, the difference between native custom elements and LWC. Let me try to summarize this. Let's take a concrete example to illustrate this. Consider a component tree composed of 3 components:
Here is the composed component tree. <x-parent id="parent">
#shadow-root
| <x-leaf id="before-container"></x-leaf>
| <x-container id="container">
| #shadow-root
| | <x-leaf id="before-slot"></x-leaf>
| | <slot></slot>
| | <x-leaf id="after-slot"></x-leaf>
| <x-leaf id="slotted"></x-leaf>
| </x-container>
| <x-leaf id="after-container"></x-leaf>
</x-parent> I reimplemented the same component tree with native custom elements (jsbin) and with LWC (source). All the components implements the Current behavior
Observations:
Proposed behaviorThis PR doesn't only affect
Proposed changes:
This PR doesn't attempt to solve all the invocation timing issues we have with native custom elements. It only attempts to course-correct the obvious discrepancies with have with |
Thanks for the analysis @pmdartus. It's important to know where we differ from the native behavior and to try to reduce it as much as possible.
Yep, based on my testing with #2724 and using native lifecycle callbacks in LWC, the main difference in timing is not in the ordering, but in the DOM / event loop timing. I.e. the ordering between the components may be the same, but under the hood, there are subtle differences (microtasks? rAF? I didn't check TBH). This is something we'll have to analyze when/if we switch to native lifecycle callbacks (all I can tell you is that it breaks plenty of our Karma tests 🙂 ). |
I don't fully understand this PR, not sure how are you doing it without holding back a reference to those vnodes... but in principle, the idea described above does make sense to me. If the tests are all passing, I'm fine with this. |
4627b82
to
5eaa8b9
Compare
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.
ok, I think I got it now.
runChildNodesDisconnectedCallback(vm); | ||
runLightChildNodesDisconnectedCallback(vm); | ||
|
||
unmountChildren(vm.children, vm.renderRoot); |
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.
It looks like unmountChildren
calls on removeVM
which has an assertion check and can potentially throw an error.
I'm not super familiar with this area but it looks like this is a new behavior that might be worth mentioning as a release note or a warning so we don't catch anyone by surprise (unless this assertion is more of an internal check).
@pmdartus what is missing here? when do we plan to merge this? |
@pmdartus with this refactor, is there a need for |
@jodarove ping |
@pmdartus It seems unlikely that we're going to merge this, and the eventual solution will be native custom element lifecycle callbacks. Should we close this PR? |
Yes, let me close this PR. I am not sure that the native CE lifecycle will solve this discrepancy. The core issue resides in the order we patch elements in the DOM. Using native lifecycle hooks will not change this as far as I understand. |
Details
This PR streamlines the component unmounting process. Currently, the component unmounting logic resides in the
vm.ts
and uses a different logic than the diffing algo. This PR corrects this and leverages the existing diffing algo to unmount components, resulting in smaller bundle size.Another noteworthy change of this PR is the removal of the
velements
property on theVM
. The property tracks all the components rendered in the shadow tree, to speed up the unmounting process. This would enable hoisting custom element VNode outside the render function (#2688). My current assumption is VDOM traversal is fast enough and the performance impact would be minimal. This has to be validated with new performance benchmarks.Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?
Currently, components in the shadow tree are unmounted in revered insertion order, while allocated children (slotted synthetic shadow DOM elements and slotted light DOM elements) are unmounted in insertion order.
With this PR, all the components are unmounted in insertion order, which changes the invocation order for
disconnectedCallback
. Additional test coverage is needed to validate this.