From 5db9e807afeea94022a24e9569d5796c10decd40 Mon Sep 17 00:00:00 2001 From: Yanzhen Yu Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] gc virtual style map when DOM has been removed --- packages/rrweb/src/replay/index.ts | 4 +++- packages/rrweb/src/replay/virtual-styles.ts | 25 +++++++++++---------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/rrweb/src/replay/index.ts b/packages/rrweb/src/replay/index.ts index cd54819d..b2f7998d 100644 --- a/packages/rrweb/src/replay/index.ts +++ b/packages/rrweb/src/replay/index.ts @@ -922,7 +922,6 @@ export class Replayer { case MouseInteractions.TouchStart: case MouseInteractions.TouchEnd: if (isSync) { - let touchActive: boolean | undefined; if (d.type === MouseInteractions.TouchStart) { this.touchActive = true; } else if (d.type === MouseInteractions.TouchEnd) { @@ -1263,6 +1262,9 @@ export class Replayer { } return this.warnNodeNotFound(d, mutation.id); } + if (this.virtualStyleRulesMap.has(target)) { + this.virtualStyleRulesMap.delete(target); + } let parent: INode | null | ShadowRoot = this.mirror.getNode( mutation.parentId, ); diff --git a/packages/rrweb/src/replay/virtual-styles.ts b/packages/rrweb/src/replay/virtual-styles.ts index 5b3d51f9..f850df27 100644 --- a/packages/rrweb/src/replay/virtual-styles.ts +++ b/packages/rrweb/src/replay/virtual-styles.ts @@ -65,18 +65,22 @@ export function applyVirtualStyleRulesToNode( storedRules: VirtualStyleRules, styleNode: HTMLStyleElement, ) { + const { sheet } = styleNode; + if (!sheet) { + // styleNode without sheet means the DOM has been removed + // so the rules no longer need to be applied + return; + } + storedRules.forEach((rule) => { if (rule.type === StyleRuleType.Insert) { try { if (Array.isArray(rule.index)) { const { positions, index } = getPositionsAndIndex(rule.index); - const nestedRule = getNestedRule( - styleNode.sheet!.cssRules, - positions, - ); + const nestedRule = getNestedRule(sheet.cssRules, positions); nestedRule.insertRule(rule.cssText, index); } else { - styleNode.sheet?.insertRule(rule.cssText, rule.index); + sheet.insertRule(rule.cssText, rule.index); } } catch (e) { /** @@ -88,13 +92,10 @@ export function applyVirtualStyleRulesToNode( try { if (Array.isArray(rule.index)) { const { positions, index } = getPositionsAndIndex(rule.index); - const nestedRule = getNestedRule( - styleNode.sheet!.cssRules, - positions, - ); + const nestedRule = getNestedRule(sheet.cssRules, positions); nestedRule.deleteRule(index || 0); } else { - styleNode.sheet?.deleteRule(rule.index); + sheet.deleteRule(rule.index); } } catch (e) { /** @@ -106,13 +107,13 @@ export function applyVirtualStyleRulesToNode( restoreSnapshotOfStyleRulesToNode(rule.cssTexts, styleNode); } else if (rule.type === StyleRuleType.SetProperty) { const nativeRule = (getNestedRule( - styleNode.sheet!.cssRules, + sheet.cssRules, rule.index, ) as unknown) as CSSStyleRule; nativeRule.style.setProperty(rule.property, rule.value, rule.priority); } else if (rule.type === StyleRuleType.RemoveProperty) { const nativeRule = (getNestedRule( - styleNode.sheet!.cssRules, + sheet.cssRules, rule.index, ) as unknown) as CSSStyleRule; nativeRule.style.removeProperty(rule.property);