From 7652621165a129f76cdafb8397a622ff1f0daf08 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 17 Oct 2023 09:57:06 +0200 Subject: [PATCH 1/3] feat: Add build flags to allow noop iframe/canvas/shadow dom managers --- packages/rrweb/src/record/iframe-manager.ts | 32 ++++++++++++++++++- packages/rrweb/src/record/index.ts | 22 ++++++++----- .../record/observers/canvas/canvas-manager.ts | 28 +++++++++++++++- .../rrweb/src/record/shadow-dom-manager.ts | 24 +++++++++++++- packages/rrweb/src/types.ts | 12 +++---- 5 files changed, 101 insertions(+), 17 deletions(-) diff --git a/packages/rrweb/src/record/iframe-manager.ts b/packages/rrweb/src/record/iframe-manager.ts index 09ff366eb4..52a03773de 100644 --- a/packages/rrweb/src/record/iframe-manager.ts +++ b/packages/rrweb/src/record/iframe-manager.ts @@ -12,7 +12,37 @@ import type { } from '@sentry-internal/rrweb-types'; import type { StylesheetManager } from './stylesheet-manager'; -export class IframeManager { +export interface IframeManagerInterface { + crossOriginIframeMirror: CrossOriginIframeMirror; + crossOriginIframeStyleMirror: CrossOriginIframeMirror; + crossOriginIframeRootIdMap: WeakMap; + + addIframe(iframeEl: HTMLIFrameElement): void; + addLoadListener(cb: (iframeEl: HTMLIFrameElement) => unknown): void; + attachIframe( + iframeEl: HTMLIFrameElement, + childSn: serializedNodeWithId, + ) : void; +} + +export class IframeManagerNoop implements IframeManagerInterface { + public crossOriginIframeMirror = new CrossOriginIframeMirror(genId); + public crossOriginIframeStyleMirror: CrossOriginIframeMirror; + public crossOriginIframeRootIdMap: WeakMap = + new WeakMap(); + + public addIframe() { + // noop + } + public addLoadListener() { + // noop + } + public attachIframe() { + // noop + } +} + +export class IframeManager implements IframeManagerInterface { private iframes: WeakMap = new WeakMap(); private crossOriginIframeMap: WeakMap = new WeakMap(); diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index c306011f18..36abd5059c 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -29,9 +29,9 @@ import { adoptedStyleSheetParam, } from '@sentry-internal/rrweb-types'; import type { CrossOriginIframeMessageEventContent } from '../types'; -import { IframeManager } from './iframe-manager'; -import { ShadowDomManager } from './shadow-dom-manager'; -import { CanvasManager } from './observers/canvas/canvas-manager'; +import { IframeManager, IframeManagerInterface, IframeManagerNoop } from './iframe-manager'; +import { ShadowDomManager, ShadowDomManagerInterface, ShadowDomManagerNoop } from './shadow-dom-manager'; +import { CanvasManager, CanvasManagerInterface, CanvasManagerNoop } from './observers/canvas/canvas-manager'; import { StylesheetManager } from './stylesheet-manager'; import ProcessedNodeManager from './processed-node-manager'; import { @@ -47,10 +47,16 @@ function wrapEvent(e: event): eventWithTime { }; } +declare global { + const __RRWEB_EXCLUDE_CANVAS__: boolean; + const __RRWEB_EXCLUDE_SHADOW_DOM__: boolean; + const __RRWEB_EXCLUDE_IFRAME__: boolean; +} + let wrappedEmit!: (e: eventWithTime, isCheckout?: boolean) => void; let takeFullSnapshot!: (isCheckout?: boolean) => void; -let canvasManager!: CanvasManager; +let canvasManager: CanvasManagerInterface; let recording = false; const mirror = createMirror(); @@ -291,7 +297,7 @@ function record( adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit, }); - const iframeManager = new IframeManager({ + const iframeManager: IframeManagerInterface = __RRWEB_EXCLUDE_IFRAME__ ? new IframeManagerNoop() : new IframeManager({ mirror, mutationCb: wrappedMutationEmit, stylesheetManager: stylesheetManager, @@ -308,13 +314,13 @@ function record( nodeMirror: mirror, crossOriginIframeMirror: iframeManager.crossOriginIframeMirror, crossOriginIframeStyleMirror: - iframeManager.crossOriginIframeStyleMirror, + iframeManager.crossOriginIframeStyleMirror, }); } const processedNodeManager = new ProcessedNodeManager(); - canvasManager = new CanvasManager({ + canvasManager = __RRWEB_EXCLUDE_CANVAS__ ? new CanvasManagerNoop() : new CanvasManager({ recordCanvas, mutationCb: wrappedCanvasMutationEmit, win: window, @@ -326,7 +332,7 @@ function record( dataURLOptions, }); - const shadowDomManager = new ShadowDomManager({ + const shadowDomManager: ShadowDomManagerInterface = __RRWEB_EXCLUDE_SHADOW_DOM__ ? new ShadowDomManagerNoop() : new ShadowDomManager({ mutationCb: wrappedMutationEmit, scrollCb: wrappedScrollEmit, bypassOptions: { diff --git a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts index d98c1777e8..93dcd9e674 100644 --- a/packages/rrweb/src/record/observers/canvas/canvas-manager.ts +++ b/packages/rrweb/src/record/observers/canvas/canvas-manager.ts @@ -28,7 +28,33 @@ type pendingCanvasMutationsMap = Map< canvasMutationWithType[] >; -export class CanvasManager { +export interface CanvasManagerInterface { + reset(): void; + freeze(): void; + unfreeze(): void; + lock(): void; + unlock(): void; +} + +export class CanvasManagerNoop implements CanvasManagerInterface { + public reset() { + // noop + } + public freeze() { + // noop + } + public unfreeze() { + // noop + } + public lock() { + // noop + } + public unlock() { + // noop + } +} + +export class CanvasManager implements CanvasManagerInterface { private pendingCanvasMutations: pendingCanvasMutationsMap = new Map(); private rafStamps: RafStamps = { latestId: 0, invokeId: null }; private mirror: Mirror; diff --git a/packages/rrweb/src/record/shadow-dom-manager.ts b/packages/rrweb/src/record/shadow-dom-manager.ts index 9e15433da0..ed814f49c6 100644 --- a/packages/rrweb/src/record/shadow-dom-manager.ts +++ b/packages/rrweb/src/record/shadow-dom-manager.ts @@ -20,7 +20,29 @@ type BypassOptions = Omit< sampling: SamplingStrategy; }; -export class ShadowDomManager { +export interface ShadowDomManagerInterface { + init(): void; + addShadowRoot(shadowRoot: ShadowRoot, doc: Document): void; + observeAttachShadow(iframeElement: HTMLIFrameElement): void; + reset(): void; +} + +export class ShadowDomManagerNoop implements ShadowDomManagerInterface { + public init() { + // noop + } + public addShadowRoot() { + // noop + } + public observeAttachShadow() { + // noop + } + public reset() { + // noop + } +} + +export class ShadowDomManager implements ShadowDomManagerInterface { private shadowDoms = new WeakSet(); private mutationCb: mutationCallBack; private scrollCb: scrollCallback; diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 7fe64fdcef..9d84e6aea4 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -8,11 +8,11 @@ import type { MaskAttributeFn, } from '@sentry-internal/rrweb-snapshot'; import type { PackFn, UnpackFn } from './packer/base'; -import type { IframeManager } from './record/iframe-manager'; -import type { ShadowDomManager } from './record/shadow-dom-manager'; +import type { IframeManager, IframeManagerInterface } from './record/iframe-manager'; +import type { ShadowDomManager, ShadowDomManagerInterface } from './record/shadow-dom-manager'; import type { Replayer } from './replay'; import type { RRNode } from '@sentry-internal/rrdom'; -import type { CanvasManager } from './record/observers/canvas/canvas-manager'; +import type { CanvasManager, CanvasManagerInterface } from './record/observers/canvas/canvas-manager'; import type { StylesheetManager } from './record/stylesheet-manager'; import type { addedNodeMutation, @@ -122,10 +122,10 @@ export type observerParam = { dataURLOptions: DataURLOptions; doc: Document; mirror: Mirror; - iframeManager: IframeManager; + iframeManager: IframeManagerInterface; stylesheetManager: StylesheetManager; - shadowDomManager: ShadowDomManager; - canvasManager: CanvasManager; + shadowDomManager: ShadowDomManagerInterface; + canvasManager: CanvasManagerInterface; processedNodeManager: ProcessedNodeManager; ignoreCSSAttributes: Set; plugins: Array<{ From bd886c48861b4f5b832cbc4023dac7e0ddadc945 Mon Sep 17 00:00:00 2001 From: mydea Date: Tue, 17 Oct 2023 07:59:20 +0000 Subject: [PATCH 2/3] Apply formatting changes --- packages/rrweb/src/record/iframe-manager.ts | 4 +- packages/rrweb/src/record/index.ts | 125 +++++++++++--------- packages/rrweb/src/types.ts | 15 ++- 3 files changed, 86 insertions(+), 58 deletions(-) diff --git a/packages/rrweb/src/record/iframe-manager.ts b/packages/rrweb/src/record/iframe-manager.ts index 52a03773de..616c137856 100644 --- a/packages/rrweb/src/record/iframe-manager.ts +++ b/packages/rrweb/src/record/iframe-manager.ts @@ -22,7 +22,7 @@ export interface IframeManagerInterface { attachIframe( iframeEl: HTMLIFrameElement, childSn: serializedNodeWithId, - ) : void; + ): void; } export class IframeManagerNoop implements IframeManagerInterface { @@ -30,7 +30,7 @@ export class IframeManagerNoop implements IframeManagerInterface { public crossOriginIframeStyleMirror: CrossOriginIframeMirror; public crossOriginIframeRootIdMap: WeakMap = new WeakMap(); - + public addIframe() { // noop } diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index 36abd5059c..ae7ac97b44 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -29,9 +29,21 @@ import { adoptedStyleSheetParam, } from '@sentry-internal/rrweb-types'; import type { CrossOriginIframeMessageEventContent } from '../types'; -import { IframeManager, IframeManagerInterface, IframeManagerNoop } from './iframe-manager'; -import { ShadowDomManager, ShadowDomManagerInterface, ShadowDomManagerNoop } from './shadow-dom-manager'; -import { CanvasManager, CanvasManagerInterface, CanvasManagerNoop } from './observers/canvas/canvas-manager'; +import { + IframeManager, + IframeManagerInterface, + IframeManagerNoop, +} from './iframe-manager'; +import { + ShadowDomManager, + ShadowDomManagerInterface, + ShadowDomManagerNoop, +} from './shadow-dom-manager'; +import { + CanvasManager, + CanvasManagerInterface, + CanvasManagerNoop, +} from './observers/canvas/canvas-manager'; import { StylesheetManager } from './stylesheet-manager'; import ProcessedNodeManager from './processed-node-manager'; import { @@ -297,13 +309,15 @@ function record( adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit, }); - const iframeManager: IframeManagerInterface = __RRWEB_EXCLUDE_IFRAME__ ? new IframeManagerNoop() : new IframeManager({ - mirror, - mutationCb: wrappedMutationEmit, - stylesheetManager: stylesheetManager, - recordCrossOriginIframes, - wrappedEmit, - }); + const iframeManager: IframeManagerInterface = __RRWEB_EXCLUDE_IFRAME__ + ? new IframeManagerNoop() + : new IframeManager({ + mirror, + mutationCb: wrappedMutationEmit, + stylesheetManager: stylesheetManager, + recordCrossOriginIframes, + wrappedEmit, + }); /** * Exposes mirror to the plugins @@ -314,55 +328,60 @@ function record( nodeMirror: mirror, crossOriginIframeMirror: iframeManager.crossOriginIframeMirror, crossOriginIframeStyleMirror: - iframeManager.crossOriginIframeStyleMirror, + iframeManager.crossOriginIframeStyleMirror, }); } const processedNodeManager = new ProcessedNodeManager(); - canvasManager = __RRWEB_EXCLUDE_CANVAS__ ? new CanvasManagerNoop() : new CanvasManager({ - recordCanvas, - mutationCb: wrappedCanvasMutationEmit, - win: window, - blockClass, - blockSelector, - unblockSelector, - mirror, - sampling: sampling.canvas, - dataURLOptions, - }); + canvasManager = __RRWEB_EXCLUDE_CANVAS__ + ? new CanvasManagerNoop() + : new CanvasManager({ + recordCanvas, + mutationCb: wrappedCanvasMutationEmit, + win: window, + blockClass, + blockSelector, + unblockSelector, + mirror, + sampling: sampling.canvas, + dataURLOptions, + }); - const shadowDomManager: ShadowDomManagerInterface = __RRWEB_EXCLUDE_SHADOW_DOM__ ? new ShadowDomManagerNoop() : new ShadowDomManager({ - mutationCb: wrappedMutationEmit, - scrollCb: wrappedScrollEmit, - bypassOptions: { - onMutation, - blockClass, - blockSelector, - unblockSelector, - maskAllText, - maskTextClass, - unmaskTextClass, - maskTextSelector, - unmaskTextSelector, - inlineStylesheet, - maskInputOptions, - dataURLOptions, - maskAttributeFn, - maskTextFn, - maskInputFn, - recordCanvas, - inlineImages, - sampling, - slimDOMOptions, - iframeManager, - stylesheetManager, - canvasManager, - keepIframeSrcFn, - processedNodeManager, - }, - mirror, - }); + const shadowDomManager: ShadowDomManagerInterface = + __RRWEB_EXCLUDE_SHADOW_DOM__ + ? new ShadowDomManagerNoop() + : new ShadowDomManager({ + mutationCb: wrappedMutationEmit, + scrollCb: wrappedScrollEmit, + bypassOptions: { + onMutation, + blockClass, + blockSelector, + unblockSelector, + maskAllText, + maskTextClass, + unmaskTextClass, + maskTextSelector, + unmaskTextSelector, + inlineStylesheet, + maskInputOptions, + dataURLOptions, + maskAttributeFn, + maskTextFn, + maskInputFn, + recordCanvas, + inlineImages, + sampling, + slimDOMOptions, + iframeManager, + stylesheetManager, + canvasManager, + keepIframeSrcFn, + processedNodeManager, + }, + mirror, + }); takeFullSnapshot = (isCheckout = false) => { wrappedEmit( diff --git a/packages/rrweb/src/types.ts b/packages/rrweb/src/types.ts index 9d84e6aea4..25eeadd631 100644 --- a/packages/rrweb/src/types.ts +++ b/packages/rrweb/src/types.ts @@ -8,11 +8,20 @@ import type { MaskAttributeFn, } from '@sentry-internal/rrweb-snapshot'; import type { PackFn, UnpackFn } from './packer/base'; -import type { IframeManager, IframeManagerInterface } from './record/iframe-manager'; -import type { ShadowDomManager, ShadowDomManagerInterface } from './record/shadow-dom-manager'; +import type { + IframeManager, + IframeManagerInterface, +} from './record/iframe-manager'; +import type { + ShadowDomManager, + ShadowDomManagerInterface, +} from './record/shadow-dom-manager'; import type { Replayer } from './replay'; import type { RRNode } from '@sentry-internal/rrdom'; -import type { CanvasManager, CanvasManagerInterface } from './record/observers/canvas/canvas-manager'; +import type { + CanvasManager, + CanvasManagerInterface, +} from './record/observers/canvas/canvas-manager'; import type { StylesheetManager } from './record/stylesheet-manager'; import type { addedNodeMutation, From a39157711a79a999a5549a53486bc8dbb460d264 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 17 Oct 2023 10:13:19 +0200 Subject: [PATCH 3/3] fix check --- packages/rrweb/src/record/index.ts | 47 ++++++++++++++++-------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/packages/rrweb/src/record/index.ts b/packages/rrweb/src/record/index.ts index ae7ac97b44..b74da44ce0 100644 --- a/packages/rrweb/src/record/index.ts +++ b/packages/rrweb/src/record/index.ts @@ -309,15 +309,16 @@ function record( adoptedStyleSheetCb: wrappedAdoptedStyleSheetEmit, }); - const iframeManager: IframeManagerInterface = __RRWEB_EXCLUDE_IFRAME__ - ? new IframeManagerNoop() - : new IframeManager({ - mirror, - mutationCb: wrappedMutationEmit, - stylesheetManager: stylesheetManager, - recordCrossOriginIframes, - wrappedEmit, - }); + const iframeManager: IframeManagerInterface = + typeof __RRWEB_EXCLUDE_IFRAME__ === 'boolean' && __RRWEB_EXCLUDE_IFRAME__ + ? new IframeManagerNoop() + : new IframeManager({ + mirror, + mutationCb: wrappedMutationEmit, + stylesheetManager: stylesheetManager, + recordCrossOriginIframes, + wrappedEmit, + }); /** * Exposes mirror to the plugins @@ -334,21 +335,23 @@ function record( const processedNodeManager = new ProcessedNodeManager(); - canvasManager = __RRWEB_EXCLUDE_CANVAS__ - ? new CanvasManagerNoop() - : new CanvasManager({ - recordCanvas, - mutationCb: wrappedCanvasMutationEmit, - win: window, - blockClass, - blockSelector, - unblockSelector, - mirror, - sampling: sampling.canvas, - dataURLOptions, - }); + canvasManager = + typeof __RRWEB_EXCLUDE_CANVAS__ === 'boolean' && __RRWEB_EXCLUDE_CANVAS__ + ? new CanvasManagerNoop() + : new CanvasManager({ + recordCanvas, + mutationCb: wrappedCanvasMutationEmit, + win: window, + blockClass, + blockSelector, + unblockSelector, + mirror, + sampling: sampling.canvas, + dataURLOptions, + }); const shadowDomManager: ShadowDomManagerInterface = + typeof __RRWEB_EXCLUDE_SHADOW_DOM__ === 'boolean' && __RRWEB_EXCLUDE_SHADOW_DOM__ ? new ShadowDomManagerNoop() : new ShadowDomManager({