Impl record iframe (#481)

* Impl record iframe

* iframe observe

* temp: add bundle file to git

* update bundle

* update with pick

* update bundle

* fix fragment map remove

* feat: add an option to determine whether to pause CSS animation when playback is paused (#428)

set pauseAnimation to true by default

* fix: elements would lose some states like scroll position because of "virtual parent" optimization (#427)

* fix: elements would lose some state like scroll position because of "virtual parent" optimization

* refactor: the bugfix code

bug: elements would lose some state like scroll position because of "virtual parent" optimization

* fix: an error occured at applyMutation(remove nodes part)

error message:
Uncaught (in promise) DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node

* pick fixes

* revert ignore file

* re-impl iframe record

* re-impl iframe replay

* code housekeeping

* move multi layer dimension calculation to replay side

* update test cases

* teardown test server

* upgrade rrweb-snapshot with iframe load timeout

Co-authored-by: Lucky Feng <yun.feng@smartx.com>
This commit is contained in:
yz-yu
2026-04-01 12:00:00 +08:00
committed by GitHub
parent b99e843e2a
commit 33f0ac5cfe
24 changed files with 1414 additions and 246 deletions

View File

@@ -14,8 +14,14 @@ import {
mutationData,
scrollData,
inputData,
DocumentDimension,
} from './types';
import { INode, IGNORED_NODE } from 'rrweb-snapshot';
import {
INode,
IGNORED_NODE,
serializedNodeWithId,
NodeType,
} from 'rrweb-snapshot';
export function on(
type: string,
@@ -527,3 +533,36 @@ export function iterateResolveTree(
iterateResolveTree(tree.children[i], cb);
}
}
type HTMLIFrameINode = HTMLIFrameElement & {
__sn: serializedNodeWithId;
};
export type AppendedIframe = {
mutationInQueue: addedNodeMutation;
builtNode: HTMLIFrameINode;
};
export function isIframeINode(node: INode): node is HTMLIFrameINode {
// node can be document fragment when using the virtual parent feature
if (!node.__sn) {
return false;
}
return node.__sn.type === NodeType.Element && node.__sn.tagName === 'iframe';
}
export function getBaseDimension(node: Node): DocumentDimension {
const frameElement = node.ownerDocument?.defaultView?.frameElement;
if (!frameElement) {
return {
x: 0,
y: 0,
};
}
const frameDimension = frameElement.getBoundingClientRect();
const frameBaseDimension = getBaseDimension(frameElement);
return {
x: frameDimension.x + frameBaseDimension.x,
y: frameDimension.y + frameBaseDimension.y,
};
}