diff --git a/src/replay/index.ts b/src/replay/index.ts index ff92c23a..97de88ba 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -318,6 +318,10 @@ export class Replayer { return baselineTime - events[0].timestamp; } + public getMirror(): Mirror { + return this.mirror; + } + /** * This API was designed to be used as play at any time offset. * Since we minimized the data collected from recorder, we do not diff --git a/src/utils.ts b/src/utils.ts index dd45009f..d579c9ae 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -34,7 +34,7 @@ export function on( return () => target.removeEventListener(type, fn, options); } -export function createMirror (): Mirror { +export function createMirror(): Mirror { return { map: {}, getId(n) { @@ -66,7 +66,40 @@ export function createMirror (): Mirror { }; } -export const mirror: Mirror = createMirror(); +// https://github.com/rrweb-io/rrweb/pull/407 +const DEPARTED_MIRROR_ACCESS_WARNING = + 'Please stop import mirror directly. Instead of that, now you can use replayer.getMirror() to access the mirror instance of a replayer.'; +export let mirror: Mirror = { + map: {}, + getId() { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + return -1; + }, + getNode() { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + return null; + }, + removeNodeFromMap() { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + }, + has() { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + return false; + }, + reset() { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + }, +}; +if (window.Proxy && window.Reflect) { + mirror = new Proxy(mirror, { + get(target, prop, receiver) { + if (prop === 'map') { + console.error(DEPARTED_MIRROR_ACCESS_WARNING); + } + return Reflect.get(target, prop, receiver); + }, + }); +} // copy from underscore and modified export function throttle( diff --git a/typings/replay/index.d.ts b/typings/replay/index.d.ts index 441552ed..9c849ae2 100644 --- a/typings/replay/index.d.ts +++ b/typings/replay/index.d.ts @@ -1,6 +1,6 @@ import { Timer } from './timer'; import { createPlayerService, createSpeedService } from './machine'; -import { eventWithTime, playerConfig, playerMetaData, Handler } from '../types'; +import { eventWithTime, playerConfig, playerMetaData, Handler, Mirror } from '../types'; import './styles/style.css'; export declare class Replayer { wrapper: HTMLDivElement; @@ -19,6 +19,7 @@ export declare class Replayer { private fragmentParentMap; private elementStateMap; private imageMap; + private mirror; private firstPlayedEvent; private newDocumentQueue; constructor(events: Array, config?: Partial); @@ -27,6 +28,7 @@ export declare class Replayer { getMetaData(): playerMetaData; getCurrentTime(): number; getTimeOffset(): number; + getMirror(): Mirror; play(timeOffset?: number): void; pause(timeOffset?: number): void; resume(timeOffset?: number): void; diff --git a/typings/utils.d.ts b/typings/utils.d.ts index b6ab536b..749487bc 100644 --- a/typings/utils.d.ts +++ b/typings/utils.d.ts @@ -1,7 +1,8 @@ import { Mirror, throttleOptions, listenerHandler, hookResetter, blockClass, eventWithTime, addedNodeMutation, removedNodeMutation, textMutation, attributeMutation, mutationData, scrollData, inputData, DocumentDimension } from './types'; import { INode, serializedNodeWithId } from 'rrweb-snapshot'; export declare function on(type: string, fn: EventListenerOrEventListenerObject, target?: Document | Window): listenerHandler; -export declare const mirror: Mirror; +export declare function createMirror(): Mirror; +export declare let mirror: Mirror; export declare function throttle(func: (arg: T) => void, wait: number, options?: throttleOptions): (arg: T) => void; export declare function hookSetter(target: T, key: string | number | symbol, d: PropertyDescriptor, isRevoked?: boolean, win?: Window & typeof globalThis): hookResetter; export declare function patch(source: {