From f3c27e989fd01b4b8e91892ea9f1987c3059145b Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 18 Jul 2024 16:03:48 -0400 Subject: [PATCH 1/6] perf: improve serialize text --- packages/rrweb/src/record/mutation.ts | 37 +++++++++++++-------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index a798441969..412ae3897b 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -19,6 +19,7 @@ import type { removedNodeMutation, addedNodeMutation, Optional, + mutationCallbackParam, } from '@rrweb/types'; import { isBlocked, @@ -133,6 +134,22 @@ class DoubleLinkedList { const moveKey = (id: number, parentId: number) => `${id}@${parentId}`; +function serializeTexts(input: textCursor[], addedIds: Set): mutationCallbackParam['texts'] { + const texts = []; + for (let i = 0; i < input.length; i++) { + const id = this.mirror.getId(input[i].node); + if (addedIds.has(id) || !this.mirror.has(id)) { + continue; + } + texts.push({ + id, + value: input[i].value, + }); + } + + return texts; +} + /** * controls behaviour of a MutationObserver */ @@ -438,25 +455,7 @@ export default class MutationBuffer { } const payload = { - texts: this.texts - .map((text) => { - const n = text.node; - if ( - n.parentNode && - (n.parentNode as Element).tagName === 'TEXTAREA' - ) { - // the node is being ignored as it isn't in the mirror, so shift mutation to attributes on parent textarea - this.genTextAreaValueMutation(n.parentNode as HTMLTextAreaElement); - } - return { - id: this.mirror.getId(n), - value: text.value, - }; - }) - // no need to include them on added elements, as they have just been serialized with up to date attribubtes - .filter((text) => !addedIds.has(text.id)) - // text mutation's id was not in the mirror map means the target node has been removed - .filter((text) => this.mirror.has(text.id)), + texts: serializeTexts(this.texts, addedIds), attributes: this.attributes .map((attribute) => { const { attributes } = attribute; From d121ec9440d058db46b387ac35905f82ab467d70 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 18 Jul 2024 16:51:12 -0400 Subject: [PATCH 2/6] add changeset --- .changeset/shaggy-bags-sneeze.md | 5 +++++ packages/rrweb/src/record/mutation.ts | 28 +++++++++++++++------------ 2 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 .changeset/shaggy-bags-sneeze.md diff --git a/.changeset/shaggy-bags-sneeze.md b/.changeset/shaggy-bags-sneeze.md new file mode 100644 index 0000000000..9eec928219 --- /dev/null +++ b/.changeset/shaggy-bags-sneeze.md @@ -0,0 +1,5 @@ +--- +"rrweb": patch +--- + +optimize attribute serialization diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 412ae3897b..4ae7a862d6 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -134,20 +134,24 @@ class DoubleLinkedList { const moveKey = (id: number, parentId: number) => `${id}@${parentId}`; -function serializeTexts(input: textCursor[], addedIds: Set): mutationCallbackParam['texts'] { +function serializeTexts( + input: textCursor[], + addedIds: Set, + mirror: Mirror, +): mutationCallbackParam['texts'] { const texts = []; - for (let i = 0; i < input.length; i++) { - const id = this.mirror.getId(input[i].node); - if (addedIds.has(id) || !this.mirror.has(id)) { - continue; - } - texts.push({ - id, - value: input[i].value, - }); + for (let i = 0; i < input.length; i++) { + const id = mirror.getId(input[i].node); + if (addedIds.has(id) || !mirror.has(id)) { + continue; } + texts.push({ + id, + value: input[i].value, + }); + } - return texts; + return texts; } /** @@ -455,7 +459,7 @@ export default class MutationBuffer { } const payload = { - texts: serializeTexts(this.texts, addedIds), + texts: serializeTexts(this.texts, addedIds, this.mirror), attributes: this.attributes .map((attribute) => { const { attributes } = attribute; From 3dd34f8379455094059366de2d6415d48ff21982 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 18 Jul 2024 17:04:28 -0400 Subject: [PATCH 3/6] fix --- packages/rrweb/src/record/mutation.ts | 48 +++++++++++++++------------ 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 4ae7a862d6..7ab2d6c0e8 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -134,26 +134,6 @@ class DoubleLinkedList { const moveKey = (id: number, parentId: number) => `${id}@${parentId}`; -function serializeTexts( - input: textCursor[], - addedIds: Set, - mirror: Mirror, -): mutationCallbackParam['texts'] { - const texts = []; - for (let i = 0; i < input.length; i++) { - const id = mirror.getId(input[i].node); - if (addedIds.has(id) || !mirror.has(id)) { - continue; - } - texts.push({ - id, - value: input[i].value, - }); - } - - return texts; -} - /** * controls behaviour of a MutationObserver */ @@ -280,6 +260,32 @@ export default class MutationBuffer { this.emit(); // clears buffer if not locked/frozen }; + private serializeTexts( + input: textCursor[], + addedIds: Set, + ): mutationCallbackParam['texts'] { + const texts = []; + for (let i = 0; i < input.length; i++) { + const n = input[i].node; + const id = this.mirror.getId(n); + if (n.parentNode && (n.parentNode as Element).tagName === 'TEXTAREA') { + // the node is being ignored as it isn't in the mirror, so shift mutation to attributes on parent textarea + this.genTextAreaValueMutation(n.parentNode as HTMLTextAreaElement); + } + + if (addedIds.has(id) || !this.mirror.has(id)) { + continue; + } + texts.push({ + id, + value: input[i].value, + }); + } + + return texts; + } + + public emit = () => { if (this.frozen || this.locked) { return; @@ -459,7 +465,7 @@ export default class MutationBuffer { } const payload = { - texts: serializeTexts(this.texts, addedIds, this.mirror), + texts: this.serializeTexts(this.texts, addedIds), attributes: this.attributes .map((attribute) => { const { attributes } = attribute; From 4ece15e1b10257c797727bff26edf3b95533c6f8 Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 18 Jul 2024 17:06:23 -0400 Subject: [PATCH 4/6] format --- packages/rrweb/src/record/mutation.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 7ab2d6c0e8..3fa341528c 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -272,7 +272,7 @@ export default class MutationBuffer { // the node is being ignored as it isn't in the mirror, so shift mutation to attributes on parent textarea this.genTextAreaValueMutation(n.parentNode as HTMLTextAreaElement); } - + if (addedIds.has(id) || !this.mirror.has(id)) { continue; } @@ -281,10 +281,9 @@ export default class MutationBuffer { value: input[i].value, }); } - + return texts; } - public emit = () => { if (this.frozen || this.locked) { From b679fc0f21245c982cc62ae92a9d4555b4b0ab9e Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 19 Sep 2024 11:44:05 -0400 Subject: [PATCH 5/6] fix bad merge --- packages/rrweb/src/record/mutation.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index b0feb706b7..aa94b15415 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -268,12 +268,13 @@ export default class MutationBuffer { const texts = []; for (let i = 0; i < input.length; i++) { const n = input[i].node; - const id = this.mirror.getId(n); - if (n.parentNode && (n.parentNode as Element).tagName === 'TEXTAREA') { + const parent = dom.parentNode(n); + if (parent && (parent as Element).tagName === 'TEXTAREA') { // the node is being ignored as it isn't in the mirror, so shift mutation to attributes on parent textarea this.genTextAreaValueMutation(n.parentNode as HTMLTextAreaElement); } + const id = this.mirror.getId(n); if (addedIds.has(id) || !this.mirror.has(id)) { continue; } From a9dd5c3993b4cf848ff4835625897870ac5011de Mon Sep 17 00:00:00 2001 From: JonasBa Date: Thu, 19 Sep 2024 11:44:58 -0400 Subject: [PATCH 6/6] use correct parent --- packages/rrweb/src/record/mutation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index aa94b15415..dc1a1e9f88 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -271,7 +271,7 @@ export default class MutationBuffer { const parent = dom.parentNode(n); if (parent && (parent as Element).tagName === 'TEXTAREA') { // the node is being ignored as it isn't in the mirror, so shift mutation to attributes on parent textarea - this.genTextAreaValueMutation(n.parentNode as HTMLTextAreaElement); + this.genTextAreaValueMutation(parent as HTMLTextAreaElement); } const id = this.mirror.getId(n);