Fix: processed-node-manager is created even in the environment that doesn't need a recorder (#1186)

* Fix: processed-node-manager is created even in the environment that doesn't need a recorder

* apply Justin's suggestion

End the RAF loop when the recorder stops
This commit is contained in:
Yun Feng
2026-04-01 12:00:00 +08:00
committed by GitHub
parent 74411fc544
commit 4bf30efbf3
6 changed files with 21 additions and 9 deletions

View File

@@ -0,0 +1,5 @@
---
'rrweb': patch
---
Fix: processed-node-manager is created even in the environment that doesn't need a recorder

View File

@@ -159,6 +159,7 @@ setInterval(save, 10 * 1000);
| collectFonts | false | 是否记录页面中的字体文件 | | collectFonts | false | 是否记录页面中的字体文件 |
| userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) | | userTriggeredOnInput | false | [什么是 `userTriggered`](https://github.com/rrweb-io/rrweb/pull/495) |
| plugins | [] | 加载插件以获得额外的录制功能. [什么是插件?](./docs/recipes/plugin.zh_CN.md) | | plugins | [] | 加载插件以获得额外的录制功能. [什么是插件?](./docs/recipes/plugin.zh_CN.md) |
| errorHandler | - | 一个可以定制化处理错误的毁掉函数,它的参数是错误对象。如果 rrweb recorder 内部的某些内容抛出错误,则会调用该回调。 |
#### 隐私 #### 隐私

View File

@@ -4,11 +4,7 @@ import {
SlimDOMOptions, SlimDOMOptions,
createMirror, createMirror,
} from 'rrweb-snapshot'; } from 'rrweb-snapshot';
import { import { initObservers, mutationBuffers } from './observer';
initObservers,
mutationBuffers,
processedNodeManager,
} from './observer';
import { import {
on, on,
getWindowWidth, getWindowWidth,
@@ -36,6 +32,7 @@ import { IframeManager } from './iframe-manager';
import { ShadowDomManager } from './shadow-dom-manager'; import { ShadowDomManager } from './shadow-dom-manager';
import { CanvasManager } from './observers/canvas/canvas-manager'; import { CanvasManager } from './observers/canvas/canvas-manager';
import { StylesheetManager } from './stylesheet-manager'; import { StylesheetManager } from './stylesheet-manager';
import ProcessedNodeManager from './processed-node-manager';
import { import {
callbackWrapper, callbackWrapper,
registerErrorHandler, registerErrorHandler,
@@ -306,6 +303,8 @@ function record<T = eventWithTime>(
}); });
} }
const processedNodeManager = new ProcessedNodeManager();
canvasManager = new CanvasManager({ canvasManager = new CanvasManager({
recordCanvas, recordCanvas,
mutationCb: wrappedCanvasMutationEmit, mutationCb: wrappedCanvasMutationEmit,
@@ -616,6 +615,7 @@ function record<T = eventWithTime>(
} }
return () => { return () => {
handlers.forEach((h) => h()); handlers.forEach((h) => h());
processedNodeManager.destroy();
recording = false; recording = false;
unregisterErrorHandler(); unregisterErrorHandler();
}; };

View File

@@ -41,7 +41,6 @@ import {
selectionCallback, selectionCallback,
} from '@rrweb/types'; } from '@rrweb/types';
import MutationBuffer from './mutation'; import MutationBuffer from './mutation';
import ProcessedNodeManager from './processed-node-manager';
import { callbackWrapper } from './error-handler'; import { callbackWrapper } from './error-handler';
type WindowWithStoredMutationObserver = IWindow & { type WindowWithStoredMutationObserver = IWindow & {
@@ -54,7 +53,6 @@ type WindowWithAngularZone = IWindow & {
}; };
export const mutationBuffers: MutationBuffer[] = []; export const mutationBuffers: MutationBuffer[] = [];
export const processedNodeManager = new ProcessedNodeManager();
// Event.path is non-standard and used in some older browsers // Event.path is non-standard and used in some older browsers
type NonStandardEvent = Omit<Event, 'composedPath'> & { type NonStandardEvent = Omit<Event, 'composedPath'> & {

View File

@@ -5,6 +5,8 @@ import type MutationBuffer from './mutation';
*/ */
export default class ProcessedNodeManager { export default class ProcessedNodeManager {
private nodeMap: WeakMap<Node, Set<MutationBuffer>> = new WeakMap(); private nodeMap: WeakMap<Node, Set<MutationBuffer>> = new WeakMap();
// Whether to continue RAF loop.
private loop = true;
constructor() { constructor() {
this.periodicallyClear(); this.periodicallyClear();
@@ -13,7 +15,7 @@ export default class ProcessedNodeManager {
private periodicallyClear() { private periodicallyClear() {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.clear(); this.clear();
this.periodicallyClear(); if (this.loop) this.periodicallyClear();
}); });
} }
@@ -31,4 +33,9 @@ export default class ProcessedNodeManager {
private clear() { private clear() {
this.nodeMap = new WeakMap(); this.nodeMap = new WeakMap();
} }
public destroy() {
// Stop the RAF loop.
this.loop = false;
}
} }

View File

@@ -574,6 +574,7 @@ export function getInputType(element: HTMLElement): Lowercase<string> | null {
return element.hasAttribute('data-rr-is-password') return element.hasAttribute('data-rr-is-password')
? 'password' ? 'password'
: element.hasAttribute('type') : element.hasAttribute('type')
? (element.getAttribute('type')!.toLowerCase() as Lowercase<string>) ? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion, @typescript-eslint/no-non-null-assertion
(element.getAttribute('type')!.toLowerCase() as Lowercase<string>)
: null; : null;
} }