Skip to content
This repository was archived by the owner on May 16, 2025. It is now read-only.

Commit ae2cca4

Browse files
committed
rrweb changes based on ue-sdk
1 parent db725cf commit ae2cca4

File tree

10 files changed

+121
-122
lines changed

10 files changed

+121
-122
lines changed

.vscode/rrweb-monorepo.code-workspace

Lines changed: 0 additions & 99 deletions
This file was deleted.

CHANGELOG_UE.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Changelog
2+
3+
This objective of this document is to track the changes being made in the rrweb package files
4+
5+
## v0.3.0
6+
7+
### Features
8+
9+
- Added image masking capability on img tags using class selector 'ue-mask'
10+
- Added masking capability on input tags using class selector 'ue-input-mask'
11+
12+
### Changes
13+
14+
/packages/rrweb-snapshot/src/snapshot.ts
15+
16+
- added img masking logic in function serializeElementNode(n, options) on line 793
17+
18+
/packages/rrweb/src/record/mutation.ts
19+
20+
- added mutation logic for masking img in function processMutation on line 670
21+
22+
/packages/rrweb/src/record/observer.ts
23+
24+
- added masking logic for input tags in function eventHandler on line 470
25+
26+
/packages/rrweb/src/record/index.ts
27+
28+
- added property 'maskInputClass' on line number 76 and 530 inside record and observe functions.
29+
30+
/packages/rrweb/src/types.ts
31+
32+
- updated types recordOptions and observeParam, added maskTextClass property in both.
33+
34+
## v0.3.4
35+
36+
### Fix
37+
38+
- Memory leak issues on IframeManager and observers
39+
40+
### Changes
41+
42+
/packages/rrweb/src/record/observer.ts
43+
44+
- flushMutationBuffers() added to clear mutationBuffers
45+
46+
/packages/rrweb/src/record/iframe-manager.ts
47+
48+
- function to cleanup handleMessage() in eventListener
49+
50+
/packages/rrweb/src/record/index.ts
51+
52+
- calling flushMutationBuffers & IframeManger cleanup() in record()

packages/rrdom-nodejs/.vscode/extensions.json

Lines changed: 0 additions & 3 deletions
This file was deleted.

packages/rrdom-nodejs/.vscode/launch.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

packages/rrweb-snapshot/src/snapshot.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
import {
23
serializedNode,
34
serializedNodeWithId,
@@ -32,6 +33,8 @@ const tagNameRegex = new RegExp('[^a-z0-9-_:]');
3233

3334
export const IGNORED_NODE = -2;
3435

36+
const BLANK_IMAGE_SRC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAABNJREFUCB1jZGBg+A/EDEwgAgQADigBA//q6GsAAAAASUVORK5CYII%3D';
37+
3538
export function genId(): number {
3639
return _id++;
3740
}
@@ -440,6 +443,7 @@ function serializeNode(
440443
mirror: Mirror;
441444
blockClass: string | RegExp;
442445
blockSelector: string | null;
446+
maskTextClass: string | RegExp;
443447
needsMask: boolean | undefined;
444448
inlineStylesheet: boolean;
445449
maskInputOptions: MaskInputOptions;
@@ -460,6 +464,7 @@ function serializeNode(
460464
mirror,
461465
blockClass,
462466
blockSelector,
467+
maskTextClass,
463468
needsMask,
464469
inlineStylesheet,
465470
maskInputOptions = {},
@@ -500,6 +505,7 @@ function serializeNode(
500505
doc,
501506
blockClass,
502507
blockSelector,
508+
maskTextClass,
503509
inlineStylesheet,
504510
maskInputOptions,
505511
maskInputFn,
@@ -600,6 +606,7 @@ function serializeElementNode(
600606
doc: Document;
601607
blockClass: string | RegExp;
602608
blockSelector: string | null;
609+
maskTextClass: string | RegExp;
603610
inlineStylesheet: boolean;
604611
maskInputOptions: MaskInputOptions;
605612
maskInputFn: MaskInputFn | undefined;
@@ -779,6 +786,32 @@ function serializeElementNode(
779786
if (image.complete && image.naturalWidth !== 0) recordInlineImage();
780787
else image.addEventListener('load', recordInlineImage);
781788
}
789+
// dont store src of img with maskTextClass class
790+
// replace src with blank png
791+
let maskTextClass = options.maskTextClass;
792+
if (tagName === 'img' && attributes.class && typeof attributes.class === 'string'
793+
&& maskTextClass && typeof maskTextClass === 'string' &&
794+
attributes.class.includes(maskTextClass)) {
795+
const image = n as HTMLImageElement;
796+
const maskImg = () => {
797+
798+
attributes.src = BLANK_IMAGE_SRC;
799+
// set width & height in style attribute of img
800+
if (attributes.style && typeof attributes.style === 'string') {
801+
if (!attributes.style.includes('width')) {
802+
attributes.style = `${attributes.style}; width: ${image.width}px;`
803+
}
804+
if (!attributes.style.includes('height')) {
805+
attributes.style = `${attributes.style}; height: ${image.height}px`;
806+
}
807+
} else {
808+
attributes.style = `width: ${image.width}px; height: ${image.height}px`;
809+
}
810+
}
811+
// The image content may not have finished loading yet.
812+
if (image.complete) maskImg();
813+
else image.onload = maskImg;
814+
}
782815
// media elements
783816
if (tagName === 'audio' || tagName === 'video') {
784817
const mediaAttributes = attributes as mediaAttributes;
@@ -1026,6 +1059,7 @@ export function serializeNodeWithId(
10261059
blockClass,
10271060
blockSelector,
10281061
needsMask,
1062+
maskTextClass,
10291063
inlineStylesheet,
10301064
maskInputOptions,
10311065
maskTextFn,

packages/rrweb/src/record/iframe-manager.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export class IframeManager {
2424
private loadListener?: (iframeEl: HTMLIFrameElement) => unknown;
2525
private stylesheetManager: StylesheetManager;
2626
private recordCrossOriginIframes: boolean;
27+
private boundHandleMessage;
2728

2829
constructor(options: {
2930
mirror: Mirror;
@@ -42,8 +43,9 @@ export class IframeManager {
4243
),
4344
);
4445
this.mirror = options.mirror;
46+
this.boundHandleMessage = this.handleMessage.bind(this);
4547
if (this.recordCrossOriginIframes) {
46-
window.addEventListener('message', this.handleMessage.bind(this));
48+
window.addEventListener('message', this.boundHandleMessage);
4749
}
4850
}
4951

@@ -299,4 +301,8 @@ export class IframeManager {
299301
});
300302
}
301303
}
304+
305+
public cleanup () {
306+
window.removeEventListener('message', this.boundHandleMessage);
307+
}
302308
}

packages/rrweb/src/record/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {
44
SlimDOMOptions,
55
createMirror,
66
} from 'rrweb-snapshot';
7-
import { initObservers, mutationBuffers } from './observer';
7+
import { flushMutationBuffers, initObservers, mutationBuffers } from './observer';
88
import {
99
on,
1010
getWindowWidth,
@@ -73,6 +73,7 @@ function record<T = eventWithTime>(
7373
ignoreClass = 'rr-ignore',
7474
ignoreSelector = null,
7575
maskTextClass = 'rr-mask',
76+
maskInputClass = 'rr-input-mask',
7677
maskTextSelector = null,
7778
inlineStylesheet = true,
7879
maskAllInputs,
@@ -526,6 +527,7 @@ function record<T = eventWithTime>(
526527
ignoreClass,
527528
ignoreSelector,
528529
maskTextClass,
530+
maskInputClass,
529531
maskTextSelector,
530532
maskInputOptions,
531533
inlineStylesheet,
@@ -617,6 +619,8 @@ function record<T = eventWithTime>(
617619
processedNodeManager.destroy();
618620
recording = false;
619621
unregisterErrorHandler();
622+
flushMutationBuffers();
623+
iframeManager.cleanup();
620624
};
621625
} catch (error) {
622626
// TODO: handle internal error

packages/rrweb/src/record/mutation.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ class DoubleLinkedList {
133133

134134
const moveKey = (id: number, parentId: number) => `${id}@${parentId}`;
135135

136+
const BLANK_IMAGE_SRC = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAABNJREFUCB1jZGBg+A/EDEwgAgQADigBA//q6GsAAAAASUVORK5CYII%3D';
137+
136138
/**
137139
* controls behaviour of a MutationObserver
138140
*/
@@ -665,6 +667,16 @@ export default class MutationBuffer {
665667
}
666668
}
667669
}
670+
// dont track img src changes if it has maskTextClass class
671+
if (m.attributeName === 'src' && (m.target as HTMLElement).nodeName === 'IMG' && this.maskTextClass && typeof this.maskTextClass === 'string' &&
672+
target.classList.toString().includes(this.maskTextClass)) {
673+
item.attributes[m.attributeName!] = transformAttribute(
674+
this.doc,
675+
toLowerCase((m.target as HTMLElement).tagName),
676+
m.attributeName!,
677+
BLANK_IMAGE_SRC,
678+
);
679+
}
668680
break;
669681
}
670682
case 'childList': {

packages/rrweb/src/record/observer.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ type WindowWithAngularZone = IWindow & {
6060
};
6161
};
6262

63-
export const mutationBuffers: MutationBuffer[] = [];
63+
export let mutationBuffers: MutationBuffer[] = [];
64+
65+
export const flushMutationBuffers = () => {
66+
mutationBuffers = [];
67+
}
6468

6569
// Event.path is non-standard and used in some older browsers
6670
type NonStandardEvent = Omit<Event, 'composedPath'> & {
@@ -418,6 +422,7 @@ function initInputObserver({
418422
ignoreSelector,
419423
maskInputOptions,
420424
maskInputFn,
425+
maskInputClass,
421426
sampling,
422427
userTriggeredOnInput,
423428
}: observerParam): listenerHandler {
@@ -466,7 +471,10 @@ function initInputObserver({
466471
value: text,
467472
maskInputFn,
468473
});
474+
} else if ((target as HTMLElement).classList.contains(maskInputClass)) {
475+
text = "*".repeat(text.length)
469476
}
477+
470478
cbWithDedup(
471479
target,
472480
userTriggeredOnInput

packages/rrweb/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type recordOptions<T> = {
5050
ignoreClass?: string;
5151
ignoreSelector?: string;
5252
maskTextClass?: maskTextClass;
53+
maskInputClass?: string;
5354
maskTextSelector?: string;
5455
maskAllInputs?: boolean;
5556
maskInputOptions?: MaskInputOptions;
@@ -90,6 +91,7 @@ export type observerParam = {
9091
ignoreClass: string;
9192
ignoreSelector: string | null;
9293
maskTextClass: maskTextClass;
94+
maskInputClass: string;
9395
maskTextSelector: string | null;
9496
maskInputOptions: MaskInputOptions;
9597
maskInputFn?: MaskInputFn;

0 commit comments

Comments
 (0)