From 925fb21bc031a345f3a8e1b47e38c3e061d8cb1d Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Fri, 15 Jan 2021 17:29:41 +0000 Subject: [PATCH 1/3] Don't store the full style attribute change, as small mutations to single style properties result in storage of a rewrite for the full style attribute, which may be very large. Had an example of a website using http://schillmania.com/projects/snowstorm/ where many direct style changes were happening every second across many 'snowflake' elements, with each attribute change looking like: "style":"color: rgb(255, 255, 255); position: absolute; width: 8px; height: 8px; font-family: arial, verdana; overflow: hidden; font-weight: normal; z-index: 0; display: block; bottom: auto; opacity: 1; padding: 0px; margin: 0px; font-size: 10px; line-height: 10px; text-align: center; vertical-align: baseline; left: 242.807px; top: 85.7332px;" even though maybe just the left/top position had been changed --- src/record/mutation.ts | 43 +++++++++++++++++---- src/replay/index.ts | 32 +++++++++------ src/types.ts | 8 +++- test/__snapshots__/integration.test.ts.snap | 29 +++++++++++++- test/utils.ts | 19 +++++---- 5 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/record/mutation.ts b/src/record/mutation.ts index 04f0065b80..a7a65b25a8 100644 --- a/src/record/mutation.ts +++ b/src/record/mutation.ts @@ -449,6 +449,7 @@ export default class MutationBuffer { break; } case 'attributes': { + const target = (m.target as HTMLElement); let value = (m.target as HTMLElement).getAttribute(m.attributeName!); if (m.attributeName === 'value') { value = maskInputValue({ @@ -472,13 +473,41 @@ export default class MutationBuffer { }; this.attributes.push(item); } - // overwrite attribute if the mutations was triggered in same time - item.attributes[m.attributeName!] = transformAttribute( - this.doc, - (m.target as HTMLElement).tagName, - m.attributeName!, - value!, - ); + if (m.attributeName === 'style') { + const old = this.doc.createElement('span'); + old.setAttribute('style', m.oldValue); + if (item.attributes['style'] === undefined) { + item.attributes['style'] = {}; + } + for (let i=0; i { - if ( - 'style' in a.attributes && - coordinatesReg.test(a.attributes.style!) - ) { - a.attributes.style = a.attributes.style!.replace( - coordinatesReg, - '$1: Npx', - ); + if ('style' in a.attributes && a.attributes.style && typeof a.attributes.style === 'object') { + for (const [k, v] of Object.entries(a.attributes.style)) { + if (Array.isArray(v)) { + if (coordinatesReg.test(k + ': ' + v[0])) { + // TODO: could round the number here instead depending on what's coming out of various test envs + a.attributes.style[k] = ['Npx', v[1]]; + } + } + coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript + } } }); s.data.adds.forEach((add) => { @@ -97,6 +99,7 @@ function stringifySnapshots(snapshots: eventWithTime[]): string { '$1: Npx', ); } + coordinatesReg.lastIndex = 0; // wow, a real wart in ECMAScript }); } delete s.timestamp; From 83072561b0707543f1799190827418143ebc2f59 Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Wed, 20 Jan 2021 15:54:35 +0000 Subject: [PATCH 2/3] More compact storage for the much more common attribute value without an `!important` flag - saves 6 chars per style attr in the json :) --- src/record/mutation.ts | 17 ++++---- src/replay/index.ts | 4 +- src/types.ts | 2 +- test/__snapshots__/integration.test.ts.snap | 47 ++++++++++++--------- test/integration.test.ts | 3 +- test/utils.ts | 6 ++- 6 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/record/mutation.ts b/src/record/mutation.ts index a7a65b25a8..2344265c27 100644 --- a/src/record/mutation.ts +++ b/src/record/mutation.ts @@ -481,14 +481,15 @@ export default class MutationBuffer { } for (let i=0; i Date: Fri, 25 Jun 2021 14:33:06 +0100 Subject: [PATCH 3/3] Fix bug: attributes weren't getting removed after changes to treatment of 'style' attributes --- src/replay/index.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/replay/index.ts b/src/replay/index.ts index de4b80a785..a9d2152c7b 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -1310,13 +1310,11 @@ export class Replayer { for (const attributeName in mutation.attributes) { if (typeof attributeName === 'string') { const value = mutation.attributes[attributeName]; - if (typeof value === 'string') { + if (value === null) { + ((target as Node) as Element).removeAttribute(attributeName); + } else if (typeof value === 'string') { try { - if (value !== null) { - ((target as Node) as Element).setAttribute(attributeName, value); - } else { - ((target as Node) as Element).removeAttribute(attributeName); - } + ((target as Node) as Element).setAttribute(attributeName, value); } catch (error) { if (this.config.showWarning) { console.warn(