Fix edge case where oldChild can become detach causing the recursive …#48
Conversation
|
Failed pendo.io/jira-ref check. Please correct Jira references in the following commits: |
megboehlert
left a comment
There was a problem hiding this comment.
Reviewed 1 of 1 files at r1, all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on @guntherjh and @juliecheng)
guntherjh
left a comment
There was a problem hiding this comment.
Fix seems fine. Any chance you can add test coverage?
Reviewed 1 of 1 files at r1, all commit messages.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on @juliecheng)
arivyiii
left a comment
There was a problem hiding this comment.
yeah i can add them in.
Reviewable status:
complete! all files reviewed, all discussions resolved (waiting on @juliecheng)
8436691 to
e467a7e
Compare
|
Failed pendo.io/jira-ref check. Please correct Jira references in the following commits: |
juliecheng
left a comment
There was a problem hiding this comment.
Reviewed 3 of 3 files at r2, all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @arivyiii)
packages/rrdom/test/diff.test.ts line 1188 at r2 (raw file):
}); it.only('should maintain correct order when duplicate node is found causing nextSibling traversal desync', () => {
nit this needs to be removed
juliecheng
left a comment
There was a problem hiding this comment.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @arivyiii)
packages/rrdom/test/diff.test.ts line 1188 at r2 (raw file):
Previously, juliecheng wrote…
nit this needs to be removed
by this i mean only :oops:
e467a7e to
466187e
Compare
|
Failed pendo.io/jira-ref check. Please correct Jira references in the following commits: |
guntherjh
left a comment
There was a problem hiding this comment.
Reviewed 1 of 3 files at r2.
Reviewable status: 2 of 3 files reviewed, 2 unresolved discussions (waiting on @arivyiii and @juliecheng)
packages/rrdom/src/diff.ts line 537 at r3 (raw file):
// Insert the new node before the current oldChild to preserve correct order. oldTree.insertBefore(newNode, oldChild);
The rest of this function uses handleInsertBefore wrapped in a try/catch. handleInsertBefore calls insertBefore under the hood, but I'm thinking we should follow the existing pattern and use handleInsertBefore wrapped in a try/catch as well.
On that note though, I'm still trying to wrap my head around all that diffChildren and the rest of the diff* functions actually do. I'm starting to think we want this type of check higher up and not part of the recursive while loop 🤔
|
Previously, guntherjh (John Henry Gunther) wrote…
I can try to do my best as least with how the diff and diffChildren is suppose to work. Diff at a high level is responsible for comparing the nodes using the It can be broken down into three levels of responsibility but I'll focus on the main two since they're related to this bug.
This is where the issue is occuring for this bug. After replacing the node the original reference to diffChildren this is the big one but it's main job is to recursively diff all the children and ensure that all of their nodes line up. the first half of the function does a pretty good job at handling this by comparing the first and last and iterating inwards until it's done comparing, along the process when it finds a diff it handles it by removing the old node and insert a node where the oldNode used to be, which looks to be a much safer operation than the replaceChild one that gets used in the diffBeforeUpdatingChildren. After it finishes aligning the nodes it will recursively iterate through each of the old nodes and new nodes. This is the part where properties and attributes get attached to the child nodes. Traversal stops here as soon as either |
guntherjh
left a comment
There was a problem hiding this comment.
Reviewable status: 2 of 3 files reviewed, 3 unresolved discussions (waiting on @arivyiii and @juliecheng)
packages/rrdom/src/diff.ts line 537 at r3 (raw file):
Previously, arivyiii (Allen Ivy) wrote…
I can try to do my best as least with how the diff and diffChildren is suppose to work.
Diff at a high level is responsible for comparing the nodes using the
newTreeas the source of truth which represents the virtual DOM. IfoldTreeandnewTreeare out of sync the goal is foroldTreeto resemblenewTreeby the end of thediffcall. This includes making sure properties and attributes are properly applied to the real DOM.It can be broken down into three levels of responsibility but I'll focus on the main two since they're related to this bug.
diffBeforeUpdatingChildrenis responsible for making sure the current nodes line up. If they do not it creates a new node fromnewTreeand replacesoldTreewith it in the DOM.This is where the issue is occuring for this bug. After replacing the node the original reference to
oldTreewhich was passed by reference becomes outdated. The parent that calleddiffstill holds onto the originaloldTreereference which has now been replaced and is no longer part of the DOM. This causes problems because the node becomes detached and no longer has aparentNodeornextSibling. That could potentially break traversal in diffChildren if diff is called from within that function.diffChildren this is the big one but it's main job is to recursively diff all the children and ensure that all of their nodes line up. the first half of the function does a pretty good job at handling this by comparing the first and last and iterating inwards until it's done comparing, along the process when it finds a diff it handles it by removing the old node and insert a node where the oldNode used to be, which looks to be a much safer operation than the replaceChild one that gets used in the diffBeforeUpdatingChildren.
After it finishes aligning the nodes it will recursively iterate through each of the old nodes and new nodes. This is the part where properties and attributes get attached to the child nodes.
Traversal stops here as soon as either
oldChildornewChildbecomes null. So even if there is more data left innewChildit assumes at this point that the nodes are aligned and it is safe to bail out of the loop
My lack of understanding here is definitely a "me" problem, but I really appreciate the explanation (it helps a ton!). My biggest worry was around how these changes would impact time complexity, but looking a bit closer, I don't think it would have much (if any) impact since the mismatch case continues.
I'm going to keep poking around in here for my own understanding. I'm also seeing some new test failures in diff.test.ts that aren't present in pendo-main. Note I am seeing can build from a html containing nested shadow doms also fail in upstream so I wouldn't worry about that one.
packages/rrdom/test/diff.test.ts line 1250 at r3 (raw file):
expect(finalIds).toEqual(oldList.map(n => String(n.id))); });
I'd remove these extra spaces
466187e to
8c4a9e6
Compare
|
Failed pendo.io/jira-ref check. Please correct Jira references in the following commits: |
guntherjh
left a comment
There was a problem hiding this comment.
Reviewed 2 of 2 files at r4, all commit messages.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on @arivyiii)
…function to end early
8c4a9e6 to
77cf879
Compare
|
Failed pendo.io/jira-ref check. Please correct Jira references in the following commits: |
|
[merge] |
|
Branch ai-fix-detached-node-in-diff-children-122273 deleted |
…function to end early
This change is