Fix: Switch to real dom before rebuilding fullsnapshot (#1139)
This commit is contained in:
5
.changeset/eight-terms-hunt.md
Normal file
5
.changeset/eight-terms-hunt.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'rrweb': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix: Switch from virtual dom to real dom before rebuilding fullsnapshot
|
||||||
5
.changeset/real-masks-explode.md
Normal file
5
.changeset/real-masks-explode.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
'rrdom': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix: If RRNode appends a single child twice, children of the node will become an infinite link list.
|
||||||
@@ -491,7 +491,7 @@ function diffChildren(
|
|||||||
} else if (newStartIndex > newEndIndex) {
|
} else if (newStartIndex > newEndIndex) {
|
||||||
for (; oldStartIndex <= oldEndIndex; oldStartIndex++) {
|
for (; oldStartIndex <= oldEndIndex; oldStartIndex++) {
|
||||||
const node = oldChildren[oldStartIndex];
|
const node = oldChildren[oldStartIndex];
|
||||||
if (!node || !parentNode.contains(node)) continue;
|
if (!node || node.parentNode !== parentNode) continue;
|
||||||
try {
|
try {
|
||||||
parentNode.removeChild(node);
|
parentNode.removeChild(node);
|
||||||
replayer.mirror.removeNodeFromMap(node);
|
replayer.mirror.removeNodeFromMap(node);
|
||||||
|
|||||||
@@ -713,6 +713,8 @@ export type CSSStyleDeclaration = Record<string, string> & {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function appendChild(parent: IRRNode, newChild: IRRNode) {
|
function appendChild(parent: IRRNode, newChild: IRRNode) {
|
||||||
|
if (newChild.parentNode) newChild.parentNode.removeChild(newChild);
|
||||||
|
|
||||||
if (parent.lastChild) {
|
if (parent.lastChild) {
|
||||||
parent.lastChild.nextSibling = newChild;
|
parent.lastChild.nextSibling = newChild;
|
||||||
newChild.previousSibling = parent.lastChild;
|
newChild.previousSibling = parent.lastChild;
|
||||||
@@ -740,6 +742,9 @@ function insertBefore(
|
|||||||
"Failed to execute 'insertBefore' on 'RRNode': The RRNode before which the new node is to be inserted is not a child of this RRNode.",
|
"Failed to execute 'insertBefore' on 'RRNode': The RRNode before which the new node is to be inserted is not a child of this RRNode.",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (newChild === refChild) return newChild;
|
||||||
|
if (newChild.parentNode) newChild.parentNode.removeChild(newChild);
|
||||||
|
|
||||||
newChild.previousSibling = refChild.previousSibling;
|
newChild.previousSibling = refChild.previousSibling;
|
||||||
refChild.previousSibling = newChild;
|
refChild.previousSibling = newChild;
|
||||||
newChild.nextSibling = refChild;
|
newChild.nextSibling = refChild;
|
||||||
|
|||||||
@@ -766,6 +766,22 @@ describe('Basic RRDocument implementation', () => {
|
|||||||
expect(node.contains(child2)).toBeTruthy();
|
expect(node.contains(child2)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can append a child with parent node', () => {
|
||||||
|
const node = document.createElement('div');
|
||||||
|
const child = document.createElement('span');
|
||||||
|
expect(node.appendChild(child)).toBe(child);
|
||||||
|
expect(node.childNodes).toEqual([child]);
|
||||||
|
expect(node.appendChild(child)).toBe(child);
|
||||||
|
expect(node.childNodes).toEqual([child]);
|
||||||
|
expect(child.parentNode).toBe(node);
|
||||||
|
|
||||||
|
const node1 = document.createElement('div');
|
||||||
|
expect(node1.appendChild(child)).toBe(child);
|
||||||
|
expect(node1.childNodes).toEqual([child]);
|
||||||
|
expect(child.parentNode).toBe(node1);
|
||||||
|
expect(node.childNodes).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
it('can insert new child before an existing child', () => {
|
it('can insert new child before an existing child', () => {
|
||||||
const node = document.createElement('div');
|
const node = document.createElement('div');
|
||||||
const child1 = document.createElement('h1');
|
const child1 = document.createElement('h1');
|
||||||
@@ -820,6 +836,25 @@ describe('Basic RRDocument implementation', () => {
|
|||||||
expect(node.contains(child1)).toBeTruthy();
|
expect(node.contains(child1)).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can insert a child with parent node', () => {
|
||||||
|
const node = document.createElement('div');
|
||||||
|
const child1 = document.createElement('h1');
|
||||||
|
expect(node.insertBefore(child1, null)).toBe(child1);
|
||||||
|
expect(node.childNodes).toEqual([child1]);
|
||||||
|
expect(node.insertBefore(child1, child1)).toBe(child1);
|
||||||
|
expect(node.childNodes).toEqual([child1]);
|
||||||
|
expect(child1.parentNode).toEqual(node);
|
||||||
|
|
||||||
|
const node2 = document.createElement('div');
|
||||||
|
const child2 = document.createElement('h2');
|
||||||
|
expect(node2.insertBefore(child2, null)).toBe(child2);
|
||||||
|
expect(node2.childNodes).toEqual([child2]);
|
||||||
|
expect(node2.insertBefore(child1, child2)).toBe(child1);
|
||||||
|
expect(node2.childNodes).toEqual([child1, child2]);
|
||||||
|
expect(child1.parentNode).toEqual(node2);
|
||||||
|
expect(node.childNodes).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
it('can remove an existing child', () => {
|
it('can remove an existing child', () => {
|
||||||
const node = document.createElement('div');
|
const node = document.createElement('div');
|
||||||
const child1 = document.createElement('h1');
|
const child1 = document.createElement('h1');
|
||||||
|
|||||||
@@ -777,6 +777,16 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally rebuilding full snapshot should not be under virtual dom environment.
|
||||||
|
* But if the order of data events has some issues, it might be possible.
|
||||||
|
* Adding this check to avoid any potential issues.
|
||||||
|
*/
|
||||||
|
if (this.usingVirtualDom) {
|
||||||
|
this.virtualDom.destroyTree();
|
||||||
|
this.usingVirtualDom = false;
|
||||||
|
}
|
||||||
|
|
||||||
this.mirror.reset();
|
this.mirror.reset();
|
||||||
rebuild(event.data.node, {
|
rebuild(event.data.node, {
|
||||||
doc: this.iframe.contentDocument,
|
doc: this.iframe.contentDocument,
|
||||||
|
|||||||
Reference in New Issue
Block a user