-
Notifications
You must be signed in to change notification settings - Fork 395
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): Remove patching hooks #2677
Conversation
79cb3f7
to
14d43ba
Compare
This is awesome. I'm a bit surprised that the perf results show some scenarios getting slightly slower. (Same data, but pasted into a spreadsheet to visualize.) If you used the default Tachometer settings, it may be worthwhile to bump it up to a sample size of 200 and timeout of 15 minutes or something. Although usually the results are repeatable (even if they're surprising). I'm still +1 on this PR since regressing server rendering in favor of DOM rendering is a worthwhile tradeoff to me. |
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.
I think this can be improved.
} | ||
} | ||
|
||
function patch(n1: VNode | null, n2: VNode, parent: ParentNode, anchor: Node | null) { |
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.
@pmdartus I wouldn't say I like that this function is doing two different things based on the parameters. If n1
is null, it is mounting (create+insert right?), otherwise patching. Then in the process*
, we make the same differentiation with a condition for isNull
(mount/patch).
imho, (because the diffing algo is already saying whether to mount/patch) a better approach will be to separate the current patch
logic into patch
and mount
and the process*
into patch*
and mount*
(you already have them for Element and CustomeElements)? (imo) Such a way is more explicit, where you have patch(null,...)
will become mount(n2,...)
and we can skip the multiple isNull
checks on the critical path of the diffing algo.
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.
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.
I'm supportive of this change!
unmount(n1, parent, true); | ||
mount(n2, parent, nextSibling(n1.elm)); | ||
return; | ||
} |
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.
None of our Jest/Karma tests hit this condition, but I'm not sure if it's impossible to hit...
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.
I think it's impossible to hit this condition. Here's why:
Call sites that already check isSameVnode()
Most places that call patch()
already check for isSameVnode()
, e.g.:
lwc/packages/@lwc/engine-core/src/framework/rendering.ts
Lines 604 to 605 in 0094a68
} else if (isSameVnode(oldEndVnode, newEndVnode)) { | |
patch(oldEndVnode, newEndVnode, parent); |
Call site that verifies key
and sel
As for the call sites that don't check, there are two. First, there's this one:
patch(elmToMove, newStartVnode, parent); |
But this one has already guaranteed that newStartVnode
and elmToMove
have the same key:
idxInOld = oldKeyToIdx[newStartVnode.key!]; |
... and the same sel
:
lwc/packages/@lwc/engine-core/src/framework/rendering.ts
Lines 632 to 635 in 0094a68
if (elmToMove.sel !== newStartVnode.sel) { | |
// New element | |
mount(newStartVnode, parent, oldStartVnode.elm!); | |
} else { |
... which is the definition of isSameVnode
:
lwc/packages/@lwc/engine-core/src/framework/vnodes.ts
Lines 89 to 91 in 0094a68
export function isSameVnode(vnode1: VNode, vnode2: VNode): boolean { | |
return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel; | |
} |
Call site that relies on static children ordering
The other call site is in updateStaticChildren
:
patch(n1, n2, parent); |
... in which case, we are dealing with two arrays of children that are already guaranteed to be the same (static), and we are taking the same item at the same index for both:
lwc/packages/@lwc/engine-core/src/framework/rendering.ts
Lines 693 to 695 in 0094a68
for (let i = c2Length - 1; i >= 0; i -= 1) { | |
const n1 = c1[i]; | |
const n2 = c2[i]; |
So I think this code is safe to remove!
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 turns out that the last scenario (updateStaticChildren
) can hit this code path, if the key
is defined outside of an iteration: #2697.
We can add code to handle this particular scenario.
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.
Good catch! I added a bunch of thoughts about this issue on the issue: #2697 (comment)
Well, thanks to ui-b2b-components tests, we now know that this condition is possible to hit. Looking into it. |
OK, added a bunch of tests, and that should cover it. |
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.
I can't approve my own PR, but I think it's in a good enough state merged. We can tackle #2697 in a follow-up one. 👍
unmount(n1, parent, true); | ||
mount(n2, parent, nextSibling(n1.elm)); | ||
return; | ||
} |
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.
Good catch! I added a bunch of thoughts about this issue on the issue: #2697 (comment)
Details
This is a follow-up to #2648. This PR finishes the transition from hooks to VNodes with a
type
property.Performance test results
Does this pull request introduce a breaking change?
Does this pull request introduce an observable change?