Skip to content

Commit d6e07c6

Browse files
authored
fix(replay): Fix replayStepper perf issues (#92167)
This PR fixes an perf regression from #83016 -- we were completely removing these style elements from the tree which causes issues when rebuilding the tree and ultimately we were hitting [this timeout](https://github.com/getsentry/rrweb/blob/6b8c4596bfc89967f2b7279bd0c054a3d8694fa7/packages/rrweb/src/replay/index.ts#L1766) too frequently, causing the browser to lockup.
1 parent 42a3695 commit d6e07c6

File tree

2 files changed

+165
-9
lines changed

2 files changed

+165
-9
lines changed

static/app/utils/replays/replayReader.spec.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,4 +494,115 @@ describe('ReplayReader', () => {
494494
]);
495495
});
496496
});
497+
498+
describe('getRRWebFramesWithoutStyles', () => {
499+
it('should remove style nodes and their content', () => {
500+
const reader = ReplayReader.factory({
501+
attachments: [
502+
{
503+
type: EventType.FullSnapshot,
504+
data: {
505+
node: {
506+
type: 1,
507+
tagName: 'html',
508+
childNodes: [],
509+
},
510+
},
511+
timestamp: 0,
512+
},
513+
{
514+
type: EventType.IncrementalSnapshot,
515+
data: {
516+
source: IncrementalSource.Mutation,
517+
adds: [
518+
{
519+
parentId: 4,
520+
nextId: 21,
521+
node: {
522+
type: 2,
523+
tagName: 'style',
524+
attributes: {
525+
'data-emotion': 'css',
526+
'data-s': '',
527+
_cssText: '.css {...} ',
528+
},
529+
childNodes: [],
530+
id: 47,
531+
},
532+
},
533+
{
534+
parentId: 414,
535+
nextId: null,
536+
node: {
537+
type: 3,
538+
textContent: '.css {...}',
539+
isStyle: true,
540+
id: 427,
541+
},
542+
},
543+
{
544+
parentId: 5,
545+
nextId: 22,
546+
node: {
547+
type: 1,
548+
tagName: 'div',
549+
attributes: {
550+
class: 'test',
551+
},
552+
childNodes: [],
553+
id: 48,
554+
},
555+
},
556+
],
557+
},
558+
timestamp: 0,
559+
},
560+
],
561+
errors: [],
562+
fetching: false,
563+
replayRecord: ReplayRecordFixture(),
564+
});
565+
566+
if (!reader) {
567+
throw new Error('Failed to create ReplayReader instance');
568+
}
569+
570+
const result = reader.getRRWebFramesWithoutStyles();
571+
572+
expect(result).toEqual([
573+
{data: {node: {childNodes: [], tagName: 'html', type: 1}}, timestamp: 0, type: 2},
574+
{
575+
data: {
576+
adds: [
577+
{
578+
nextId: 21,
579+
node: {attributes: {}, childNodes: [], id: 47, tagName: 'style', type: 2},
580+
parentId: 4,
581+
},
582+
{
583+
nextId: null,
584+
node: {id: 427, isStyle: true, textContent: '', type: 3},
585+
parentId: 414,
586+
},
587+
{
588+
nextId: 22,
589+
node: {
590+
attributes: {class: 'test'},
591+
childNodes: [],
592+
id: 48,
593+
tagName: 'div',
594+
type: 1,
595+
},
596+
parentId: 5,
597+
},
598+
],
599+
source: 0,
600+
},
601+
timestamp: 0,
602+
type: 3,
603+
},
604+
{data: {payload: {}, tag: 'replay.end'}, timestamp: expect.any(Number), type: 5},
605+
]);
606+
});
607+
});
497608
});

static/app/utils/replays/replayReader.tsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,8 @@ export default class ReplayReader {
571571
});
572572

573573
/**
574-
* Filter out style mutations as they can cause perf problems especially when
575-
* used in replayStepper
574+
* Do not include style mutation content as they can cause perf problems when
575+
* used in replayStepper. However, we need to keep the nodes itself as to not affect the tree structure.
576576
*/
577577
getRRWebFramesWithoutStyles = memoize(() => {
578578
return this.getRRWebFrames().map(e => {
@@ -581,17 +581,62 @@ export default class ReplayReader {
581581
'source' in e.data &&
582582
e.data.source === IncrementalSource.Mutation
583583
) {
584+
// Example `data` object:
585+
// [{
586+
// "parentId": 4,
587+
// "nextId": 21,
588+
// "node": {
589+
// "type": 2,
590+
// "tagName": "style",
591+
// "attributes": {
592+
// "data-emotion": "css",
593+
// "data-s": "",
594+
// "_cssText": ".css {...} "
595+
// },
596+
// "childNodes": [],
597+
// "id": 47
598+
// }
599+
// },
600+
// {
601+
// "parentId": 414,
602+
// "nextId": null,
603+
// "node": {
604+
// "type": 3,
605+
// "textContent": ".css {...}",
606+
// "isStyle": true,
607+
// "id": 427
608+
// }
609+
// }
610+
// ]
611+
584612
return {
585613
...e,
586614
data: {
587615
...e.data,
588-
adds: e.data.adds.filter(
589-
add =>
590-
!(
591-
(add.node.type === 3 && add.node.isStyle) ||
592-
(add.node.type === 2 && add.node.tagName === 'style')
593-
)
594-
),
616+
adds: e.data.adds.map(add => {
617+
if (add.node.type === 3 && add.node.isStyle) {
618+
return {
619+
...add,
620+
node: {
621+
...add.node,
622+
textContent: '',
623+
},
624+
};
625+
}
626+
627+
if (add.node.type === 2 && add.node.tagName === 'style') {
628+
return {
629+
...add,
630+
node: {
631+
...add.node,
632+
attributes: {},
633+
childNodes: [],
634+
},
635+
};
636+
}
637+
638+
return add;
639+
}),
595640
},
596641
};
597642
}

0 commit comments

Comments
 (0)