fix: move patch function into utils to improve bundling (#1631)

* fix: move patch function into utils to improve bundling

---------

Co-authored-by: pauldambra <pauldambra@users.noreply.github.com>
Co-authored-by: Justin Halsall <Juice10@users.noreply.github.com>
This commit is contained in:
Paul D'Ambra
2026-04-01 12:00:00 +08:00
committed by GitHub
parent 636b02780e
commit bd367c2a73
13 changed files with 71 additions and 54 deletions

View File

@@ -0,0 +1,8 @@
---
"@rrweb/rrweb-plugin-console-record": patch
"@rrweb/record": patch
"rrweb": patch
"@rrweb/utils": patch
---
Move patch function into @rrweb/utils to improve bundling

View File

@@ -53,6 +53,7 @@
"puppeteer": "^20.9.0" "puppeteer": "^20.9.0"
}, },
"peerDependencies": { "peerDependencies": {
"rrweb": "^2.0.0-alpha.18" "rrweb": "^2.0.0-alpha.18",
"@rrweb/utils": "^2.0.0-alpha.18"
} }
} }

View File

@@ -1,5 +1,5 @@
import type { listenerHandler, RecordPlugin, IWindow } from '@rrweb/types'; import type { listenerHandler, RecordPlugin, IWindow } from '@rrweb/types';
import { utils } from 'rrweb'; import { patch } from '@rrweb/utils';
import { ErrorStackParser, StackFrame } from './error-stack-parser'; import { ErrorStackParser, StackFrame } from './error-stack-parser';
import { stringify } from './stringify'; import { stringify } from './stringify';
@@ -183,7 +183,7 @@ function initLogObserver(
}; };
} }
// replace the logger.{level}. return a restore function // replace the logger.{level}. return a restore function
return utils.patch( return patch(
_logger, _logger,
level, level,
(original: (...args: Array<unknown>) => void) => { (original: (...args: Array<unknown>) => void) => {

View File

@@ -56,7 +56,8 @@
}, },
"dependencies": { "dependencies": {
"@rrweb/types": "^2.0.0-alpha.18", "@rrweb/types": "^2.0.0-alpha.18",
"rrweb": "^2.0.0-alpha.18" "rrweb": "^2.0.0-alpha.18",
"@rrweb/utils": "^2.0.0-alpha.18"
}, },
"browserslist": [ "browserslist": [
"supports es6-class" "supports es6-class"

View File

@@ -11,6 +11,9 @@
}, },
{ {
"path": "../rrweb" "path": "../rrweb"
},
{
"path": "../utils"
} }
] ]
} }

View File

@@ -15,10 +15,10 @@ import {
getWindowWidth, getWindowWidth,
isBlocked, isBlocked,
legacy_isTouchEvent, legacy_isTouchEvent,
patch,
StyleSheetMirror, StyleSheetMirror,
nowTimestamp, nowTimestamp,
} from '../utils'; } from '../utils';
import { patch } from '@rrweb/utils';
import type { observerParam, MutationBufferParam } from '../types'; import type { observerParam, MutationBufferParam } from '../types';
import { import {
IncrementalSource, IncrementalSource,

View File

@@ -5,7 +5,8 @@ import {
type IWindow, type IWindow,
type listenerHandler, type listenerHandler,
} from '@rrweb/types'; } from '@rrweb/types';
import { hookSetter, isBlocked, patch } from '../../../utils'; import { hookSetter, isBlocked } from '../../../utils';
import { patch } from '@rrweb/utils';
import { serializeArgs } from './serialize-args'; import { serializeArgs } from './serialize-args';
export default function initCanvas2DMutationObserver( export default function initCanvas2DMutationObserver(

View File

@@ -1,6 +1,7 @@
import type { ICanvas } from 'rrweb-snapshot'; import type { ICanvas } from 'rrweb-snapshot';
import type { blockClass, IWindow, listenerHandler } from '@rrweb/types'; import type { blockClass, IWindow, listenerHandler } from '@rrweb/types';
import { isBlocked, patch } from '../../../utils'; import { isBlocked } from '../../../utils';
import { patch } from '@rrweb/utils';
function getNormalizedContextName(contextType: string) { function getNormalizedContextName(contextType: string) {
return contextType === 'experimental-webgl' ? 'webgl' : contextType; return contextType === 'experimental-webgl' ? 'webgl' : contextType;

View File

@@ -6,7 +6,8 @@ import {
type IWindow, type IWindow,
type listenerHandler, type listenerHandler,
} from '@rrweb/types'; } from '@rrweb/types';
import { hookSetter, isBlocked, patch } from '../../../utils'; import { hookSetter, isBlocked } from '../../../utils';
import { patch } from '@rrweb/utils';
import { saveWebGLVar, serializeArgs } from './serialize-args'; import { saveWebGLVar, serializeArgs } from './serialize-args';
function patchGLPrototype( function patchGLPrototype(

View File

@@ -9,10 +9,10 @@ import {
initScrollObserver, initScrollObserver,
initAdoptedStyleSheetObserver, initAdoptedStyleSheetObserver,
} from './observer'; } from './observer';
import { patch, inDom } from '../utils'; import { inDom } from '../utils';
import type { Mirror } from 'rrweb-snapshot'; import type { Mirror } from 'rrweb-snapshot';
import { isNativeShadowDom } from 'rrweb-snapshot'; import { isNativeShadowDom } from 'rrweb-snapshot';
import dom from '@rrweb/utils'; import dom, { patch } from '@rrweb/utils';
type BypassOptions = Omit< type BypassOptions = Omit<
MutationBufferParam, MutationBufferParam,

View File

@@ -127,49 +127,6 @@ export function hookSetter<T>(
return () => hookSetter(target, key, original || {}, true); return () => hookSetter(target, key, original || {}, true);
} }
// copy from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts
export function patch(
source: { [key: string]: any },
name: string,
replacement: (...args: unknown[]) => unknown,
): () => void {
try {
if (!(name in source)) {
return () => {
//
};
}
const original = source[name] as () => unknown;
const wrapped = replacement(original);
// Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work
// otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
if (typeof wrapped === 'function') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
wrapped.prototype = wrapped.prototype || {};
Object.defineProperties(wrapped, {
__rrweb_original__: {
enumerable: false,
value: original,
},
});
}
source[name] = wrapped;
return () => {
source[name] = original;
};
} catch {
return () => {
//
};
// This can throw if multiple fill happens on a global object like XMLHttpRequest
// Fixes https://github.com/getsentry/sentry-javascript/issues/2043
}
}
// guard against old third party libraries which redefine Date.now // guard against old third party libraries which redefine Date.now
let nowTimestamp = Date.now; let nowTimestamp = Date.now;

View File

@@ -222,6 +222,49 @@ export function mutationObserverCtor(): (typeof MutationObserver)['prototype']['
return getUntaintedPrototype('MutationObserver').constructor; return getUntaintedPrototype('MutationObserver').constructor;
} }
// copy from https://github.com/getsentry/sentry-javascript/blob/b2109071975af8bf0316d3b5b38f519bdaf5dc15/packages/utils/src/object.ts
export function patch(
source: { [key: string]: any },
name: string,
replacement: (...args: unknown[]) => unknown,
): () => void {
try {
if (!(name in source)) {
return () => {
//
};
}
const original = source[name] as () => unknown;
const wrapped = replacement(original);
// Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work
// otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
if (typeof wrapped === 'function') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
wrapped.prototype = wrapped.prototype || {};
Object.defineProperties(wrapped, {
__rrweb_original__: {
enumerable: false,
value: original,
},
});
}
source[name] = wrapped;
return () => {
source[name] = original;
};
} catch {
return () => {
//
};
// This can throw if multiple fill happens on a global object like XMLHttpRequest
// Fixes https://github.com/getsentry/sentry-javascript/issues/2043
}
}
export default { export default {
childNodes, childNodes,
parentNode, parentNode,
@@ -235,4 +278,5 @@ export default {
querySelector, querySelector,
querySelectorAll, querySelectorAll,
mutationObserver: mutationObserverCtor, mutationObserver: mutationObserverCtor,
patch,
}; };