-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: angular change detection mutation observer (#1531)
- Loading branch information
1 parent
cb08a81
commit 6870579
Showing
5 changed files
with
119 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module.exports = { | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
description: | ||
'Disallow direct use of MutationObserver and enforce importing NativeMutationObserver from global.ts', | ||
category: 'Best Practices', | ||
recommended: false, | ||
}, | ||
schema: [], | ||
messages: { | ||
noDirectMutationObserver: | ||
'Direct use of MutationObserver is not allowed. Use NativeMutationObserver from global.ts instead.', | ||
}, | ||
}, | ||
create(context) { | ||
return { | ||
NewExpression(node) { | ||
if (node.callee.type === 'Identifier' && node.callee.name === 'MutationObserver') { | ||
context.report({ | ||
node, | ||
messageId: 'noDirectMutationObserver', | ||
}) | ||
} | ||
}, | ||
} | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* adapted from https://github.com/getsentry/sentry-javascript/blob/72751dacb88c5b970d8bac15052ee8e09b28fd5d/packages/browser-utils/src/getNativeImplementation.ts#L27 | ||
* and https://github.com/PostHog/rrweb/blob/804380afbb1b9bed70b8792cb5a25d827f5c0cb5/packages/utils/src/index.ts#L31 | ||
* after a number of performance reports from Angular users | ||
*/ | ||
|
||
import { AssignableWindow } from './globals' | ||
import { isAngularZonePatchedFunction, isFunction, isNativeFunction } from './type-utils' | ||
import { logger } from './logger' | ||
|
||
interface NativeImplementationsCache { | ||
MutationObserver: typeof MutationObserver | ||
} | ||
|
||
const cachedImplementations: Partial<NativeImplementationsCache> = {} | ||
|
||
export function getNativeImplementation<T extends keyof NativeImplementationsCache>( | ||
name: T, | ||
assignableWindow: AssignableWindow | ||
): NativeImplementationsCache[T] { | ||
const cached = cachedImplementations[name] | ||
if (cached) { | ||
return cached | ||
} | ||
|
||
let impl = assignableWindow[name] as NativeImplementationsCache[T] | ||
|
||
if (isNativeFunction(impl) && !isAngularZonePatchedFunction(impl)) { | ||
return (cachedImplementations[name] = impl.bind(assignableWindow) as NativeImplementationsCache[T]) | ||
} | ||
|
||
const document = assignableWindow.document | ||
if (document && isFunction(document.createElement)) { | ||
try { | ||
const sandbox = document.createElement('iframe') | ||
sandbox.hidden = true | ||
document.head.appendChild(sandbox) | ||
const contentWindow = sandbox.contentWindow | ||
if (contentWindow && (contentWindow as any)[name]) { | ||
impl = (contentWindow as any)[name] as NativeImplementationsCache[T] | ||
} | ||
document.head.removeChild(sandbox) | ||
} catch (e) { | ||
// Could not create sandbox iframe, just use assignableWindow.xxx | ||
logger.warn(`Could not create sandbox iframe for ${name} check, bailing to assignableWindow.${name}: `, e) | ||
} | ||
} | ||
|
||
// Sanity check: This _should_ not happen, but if it does, we just skip caching... | ||
// This can happen e.g. in tests where fetch may not be available in the env, or similar. | ||
if (!impl || !isFunction(impl)) { | ||
return impl | ||
} | ||
|
||
return (cachedImplementations[name] = impl.bind(assignableWindow) as NativeImplementationsCache[T]) | ||
} | ||
|
||
export function getNativeMutationObserverImplementation(assignableWindow: AssignableWindow): typeof MutationObserver { | ||
return getNativeImplementation('MutationObserver', assignableWindow) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters