Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a custom Window object (aka: allow injection of rrweb from an iframe) #1023

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ The parameter of `rrweb.record` accepts the following options.
| inlineImages | false | whether to record the image content |
| collectFonts | false | whether to collect fonts in the website |
| userTriggeredOnInput | false | whether to add `userTriggered` on input events that indicates if this event was triggered directly by the user or not. [What is `userTriggered`?](https://github.com/rrweb-io/rrweb/pull/495) |
| window | window | Window object to record. When rrweb is loaded from an iframe, inject here the parent `window` Element. |
| plugins | [] | load plugins to provide extended record functions. [What is plugins?](./docs/recipes/plugin.md) |

#### Privacy
Expand Down
1 change: 1 addition & 0 deletions guide.zh_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ setInterval(save, 10 * 1000);
| inlineImages | false | 是否将图片内容记内联录制 |
| collectFonts | false | 是否记录页面中的字体文件 |
| userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) |
| window | window | |
| plugins | [] | 加载插件以获得额外的录制功能. [什么是插件?](./docs/recipes/plugin.zh_CN.md) |

#### 隐私
Expand Down
55 changes: 32 additions & 23 deletions packages/rrweb/src/record/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
scrollCallback,
canvasMutationParam,
adoptedStyleSheetParam,
IWindow,
} from '../types';
import { IframeManager } from './iframe-manager';
import { ShadowDomManager } from './shadow-dom-manager';
Expand Down Expand Up @@ -71,10 +72,12 @@ function record<T = eventWithTime>(
userTriggeredOnInput = false,
collectFonts = false,
inlineImages = false,
window: _win = window,
plugins,
keepIframeSrcFn = () => false,
ignoreCSSAttributes = new Set([]),
} = options;
const win = (_win as unknown) as IWindow;

// runtime checks for user options
if (!emit) {
Expand Down Expand Up @@ -250,7 +253,7 @@ function record<T = eventWithTime>(
canvasManager = new CanvasManager({
recordCanvas,
mutationCb: wrappedCanvasMutationEmit,
win: window,
win,
blockClass,
blockSelector,
mirror,
Expand All @@ -259,6 +262,7 @@ function record<T = eventWithTime>(
});

const shadowDomManager = new ShadowDomManager({
win,
mutationCb: wrappedMutationEmit,
scrollCb: wrappedScrollEmit,
bypassOptions: {
Expand All @@ -279,6 +283,7 @@ function record<T = eventWithTime>(
stylesheetManager,
canvasManager,
keepIframeSrcFn,
window: win,
},
mirror,
});
Expand All @@ -288,9 +293,9 @@ function record<T = eventWithTime>(
wrapEvent({
type: EventType.Meta,
data: {
href: window.location.href,
width: getWindowWidth(),
height: getWindowHeight(),
href: win.location.href,
width: getWindowWidth(win),
height: getWindowHeight(win),
},
}),
isCheckout,
Expand All @@ -300,7 +305,7 @@ function record<T = eventWithTime>(
stylesheetManager.reset();

mutationBuffers.forEach((buf) => buf.lock()); // don't allow any mirror modifications during snapshotting
const node = snapshot(document, {
const node = snapshot(win.document, {
mirror,
blockClass,
blockSelector,
Expand All @@ -321,7 +326,7 @@ function record<T = eventWithTime>(
stylesheetManager.trackLinkElement(n as HTMLLinkElement);
}
if (hasShadowRoot(n)) {
shadowDomManager.addShadowRoot(n.shadowRoot, document);
shadowDomManager.addShadowRoot(n.shadowRoot, win.document);
}
},
onIframeLoad: (iframe, childSn) => {
Expand All @@ -345,18 +350,18 @@ function record<T = eventWithTime>(
node,
initialOffset: {
left:
window.pageXOffset !== undefined
? window.pageXOffset
: document?.documentElement.scrollLeft ||
document?.body?.parentElement?.scrollLeft ||
document?.body?.scrollLeft ||
win.pageXOffset !== undefined
? win.pageXOffset
: win.document?.documentElement.scrollLeft ||
win.document?.body?.parentElement?.scrollLeft ||
win.document?.body?.scrollLeft ||
0,
top:
window.pageYOffset !== undefined
? window.pageYOffset
: document?.documentElement.scrollTop ||
document?.body?.parentElement?.scrollTop ||
document?.body?.scrollTop ||
win.pageYOffset !== undefined
? win.pageYOffset
: win.document?.documentElement.scrollTop ||
win.document?.body?.parentElement?.scrollTop ||
win.document?.body?.scrollTop ||
0,
},
},
Expand All @@ -365,10 +370,13 @@ function record<T = eventWithTime>(
mutationBuffers.forEach((buf) => buf.unlock()); // generate & emit any mutations that happened during snapshotting, as can now apply against the newly built mirror

// Some old browsers don't support adoptedStyleSheets.
if (document.adoptedStyleSheets && document.adoptedStyleSheets.length > 0)
if (
win.document.adoptedStyleSheets &&
win.document.adoptedStyleSheets.length > 0
)
stylesheetManager.adoptStyleSheets(
document.adoptedStyleSheets,
mirror.getId(document),
win.document.adoptedStyleSheets,
mirror.getId(win.document),
);
};

Expand Down Expand Up @@ -493,6 +501,7 @@ function record<T = eventWithTime>(
inlineImages,
userTriggeredOnInput,
collectFonts,
window: win,
doc,
maskInputFn,
maskTextFn,
Expand Down Expand Up @@ -534,11 +543,11 @@ function record<T = eventWithTime>(

const init = () => {
takeFullSnapshot();
handlers.push(observe(document));
handlers.push(observe(win.document));
};
if (
document.readyState === 'interactive' ||
document.readyState === 'complete'
win.document.readyState === 'interactive' ||
win.document.readyState === 'complete'
) {
init();
} else {
Expand All @@ -554,7 +563,7 @@ function record<T = eventWithTime>(
);
init();
},
window,
win,
),
);
}
Expand Down
7 changes: 6 additions & 1 deletion packages/rrweb/src/record/mutation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export default class MutationBuffer {
private inlineImages: observerParam['inlineImages'];
private slimDOMOptions: observerParam['slimDOMOptions'];
private dataURLOptions: observerParam['dataURLOptions'];
private window: observerParam['window'];
private doc: observerParam['doc'];
private mirror: observerParam['mirror'];
private iframeManager: observerParam['iframeManager'];
Expand All @@ -193,6 +194,7 @@ export default class MutationBuffer {
'inlineImages',
'slimDOMOptions',
'dataURLOptions',
'window',
'doc',
'mirror',
'iframeManager',
Expand Down Expand Up @@ -321,7 +323,10 @@ export default class MutationBuffer {
);
}
if (hasShadowRoot(n)) {
this.shadowDomManager.addShadowRoot(n.shadowRoot, document);
this.shadowDomManager.addShadowRoot(
n.shadowRoot,
this.window.document,
);
}
},
onIframeLoad: (iframe, childSn) => {
Expand Down
17 changes: 9 additions & 8 deletions packages/rrweb/src/record/observer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function initMutationObserver(
// see mutation.ts for details
mutationBuffer.init(options);
let mutationObserverCtor =
window.MutationObserver ||
options.window.MutationObserver ||
/**
* Some websites may disable MutationObserver by removing it from the window object.
* If someone is using rrweb to build a browser extention or things like it, they
Expand All @@ -96,17 +96,17 @@ export function initMutationObserver(
* Then they can do this to store the native MutationObserver:
* window.__rrMutationObserver = MutationObserver
*/
(window as WindowWithStoredMutationObserver).__rrMutationObserver;
const angularZoneSymbol = (window as WindowWithAngularZone)?.Zone?.__symbol__?.(
(options.window as WindowWithStoredMutationObserver).__rrMutationObserver;
const angularZoneSymbol = (options.window as WindowWithAngularZone)?.Zone?.__symbol__?.(
'MutationObserver',
);
if (
angularZoneSymbol &&
((window as unknown) as Record<string, typeof MutationObserver>)[
((options.window as unknown) as Record<string, typeof MutationObserver>)[
angularZoneSymbol
]
) {
mutationObserverCtor = ((window as unknown) as Record<
mutationObserverCtor = ((options.window as unknown) as Record<
string,
typeof MutationObserver
>)[angularZoneSymbol];
Expand Down Expand Up @@ -299,13 +299,14 @@ export function initScrollObserver({
}

function initViewportResizeObserver({
window: win,
viewportResizeCb,
}: observerParam): listenerHandler {
let lastH = -1;
let lastW = -1;
const updateDimension = throttle(() => {
const height = getWindowHeight();
const width = getWindowWidth();
const height = getWindowHeight(win);
const width = getWindowWidth(win);
if (lastH !== height || lastW !== width) {
viewportResizeCb({
width: Number(width),
Expand All @@ -315,7 +316,7 @@ function initViewportResizeObserver({
lastW = width;
}
}, 200);
return on('resize', updateDimension, window);
return on('resize', updateDimension, win);
}

function wrapEventWithUserTriggeredFlag(
Expand Down
5 changes: 5 additions & 0 deletions packages/rrweb/src/record/shadow-dom-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type {
scrollCallback,
MutationBufferParam,
SamplingStrategy,
IWindow,
} from '../types';
import {
initMutationObserver,
Expand All @@ -21,6 +22,7 @@ type BypassOptions = Omit<
};

export class ShadowDomManager {
private win: IWindow;
private shadowDoms = new WeakSet<ShadowRoot>();
private mutationCb: mutationCallBack;
private scrollCb: scrollCallback;
Expand All @@ -29,11 +31,13 @@ export class ShadowDomManager {
private restorePatches: (() => void)[] = [];

constructor(options: {
win: IWindow;
mutationCb: mutationCallBack;
scrollCb: scrollCallback;
bypassOptions: BypassOptions;
mirror: Mirror;
}) {
this.win = options.win;
this.mutationCb = options.mutationCb;
this.scrollCb = options.scrollCb;
this.bypassOptions = options.bypassOptions;
Expand Down Expand Up @@ -65,6 +69,7 @@ export class ShadowDomManager {
initMutationObserver(
{
...this.bypassOptions,
window: this.win,
doc,
mutationCb: this.mutationCb,
mirror: this.mirror,
Expand Down
3 changes: 3 additions & 0 deletions packages/rrweb/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ export type recordOptions<T> = {
userTriggeredOnInput?: boolean;
collectFonts?: boolean;
inlineImages?: boolean;
window?: Window;
plugins?: RecordPlugin[];
// departed, please use sampling options
mousemoveWait?: number;
Expand Down Expand Up @@ -299,6 +300,7 @@ export type observerParam = {
collectFonts: boolean;
slimDOMOptions: SlimDOMOptions;
dataURLOptions: DataURLOptions;
window: IWindow;
doc: Document;
mirror: Mirror;
iframeManager: IframeManager;
Expand Down Expand Up @@ -333,6 +335,7 @@ export type MutationBufferParam = Pick<
| 'inlineImages'
| 'slimDOMOptions'
| 'dataURLOptions'
| 'window'
| 'doc'
| 'mirror'
| 'iframeManager'
Expand Down
18 changes: 10 additions & 8 deletions packages/rrweb/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,21 @@ export function patch(
}
}

export function getWindowHeight(): number {
export function getWindowHeight(win: Window): number {
return (
window.innerHeight ||
(document.documentElement && document.documentElement.clientHeight) ||
(document.body && document.body.clientHeight)
win.innerHeight ||
(win.document.documentElement &&
win.document.documentElement.clientHeight) ||
(win.document.body && win.document.body.clientHeight)
);
}

export function getWindowWidth(): number {
export function getWindowWidth(win: Window): number {
return (
window.innerWidth ||
(document.documentElement && document.documentElement.clientWidth) ||
(document.body && document.body.clientWidth)
win.innerWidth ||
(win.document.documentElement &&
win.document.documentElement.clientWidth) ||
(win.document.body && win.document.body.clientWidth)
);
}

Expand Down
Loading