-
Notifications
You must be signed in to change notification settings - Fork 138
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 clashing
- Loading branch information
1 parent
cb08a81
commit dcd4691
Showing
19 changed files
with
145 additions
and
0 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,43 @@ | ||
module.exports = { | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
description: 'Ensure setTimeout is only used when imported from utils/prototype-utils', | ||
category: 'Best Practices', | ||
recommended: false, | ||
}, | ||
schema: [], | ||
messages: { | ||
restrictedImport: 'setTimeout must be imported from utils/prototype-utils.', | ||
}, | ||
}, | ||
create(context) { | ||
let importedFromTargetFile = false | ||
const targetFileName = 'utils/prototype-utils' // Simplified target check | ||
|
||
return { | ||
ImportDeclaration(node) { | ||
if (node.source.value.includes(targetFileName)) { | ||
// Check if 'setTimeout' is specifically imported | ||
const importedSpecifiers = node.specifiers.map( | ||
(specifier) => specifier.imported && specifier.imported.name | ||
) | ||
if (importedSpecifiers.includes('setTimeout')) { | ||
importedFromTargetFile = true | ||
} | ||
} | ||
}, | ||
CallExpression(node) { | ||
// Check if `setTimeout` is called | ||
if (node.callee.type === 'Identifier' && node.callee.name === 'setTimeout') { | ||
if (!importedFromTargetFile) { | ||
context.report({ | ||
node, | ||
messageId: 'restrictedImport', | ||
}) | ||
} | ||
} | ||
}, | ||
} | ||
}, | ||
} |
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
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
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
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
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
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,81 @@ | ||
/** | ||
* 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 { isFunction, isNativeFunction } from './type-utils' | ||
import { logger } from './logger' | ||
|
||
interface NativeImplementationsCache { | ||
setTimeout: typeof assignableWindow.setTimeout | ||
} | ||
|
||
const cachedImplementations: Partial<NativeImplementationsCache> = {} | ||
|
||
/** | ||
* Get the native implementation of a browser function. | ||
* | ||
* This can be used to ensure we get an unwrapped version of a function, in cases where a wrapped function can lead to problems. | ||
* | ||
* The following methods can be retrieved: | ||
* - `setTimeout`: This can be wrapped by e.g. Angular, causing change detection to be triggered. | ||
* - `mutationObserverCtor`: This can be wrapped by e.g. Angular, causing change detection to be triggered. | ||
*/ | ||
export function getNativeImplementation<T extends keyof NativeImplementationsCache>( | ||
name: T | ||
): NativeImplementationsCache[T] { | ||
const cached = cachedImplementations[name] | ||
if (cached) { | ||
return cached | ||
} | ||
|
||
let impl = assignableWindow[name] as NativeImplementationsCache[T] | ||
|
||
// Fast path to avoid DOM I/O | ||
if (isNativeFunction(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[name]) { | ||
impl = contentWindow[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) { | ||
return impl | ||
} | ||
|
||
return (cachedImplementations[name] = impl.bind(assignableWindow) as NativeImplementationsCache[T]) | ||
} | ||
|
||
/** Clear a cached implementation. */ | ||
export function clearCachedImplementation(name: keyof NativeImplementationsCache): void { | ||
cachedImplementations[name] = undefined | ||
} | ||
|
||
/** | ||
* Get an unwrapped `setTimeout` method. | ||
* This ensures that even if e.g. Angular wraps `setTimeout`, we get the native implementation, | ||
* avoiding triggering change detection. | ||
*/ | ||
export function setTimeout( | ||
...rest: Parameters<typeof assignableWindow.setTimeout> | ||
): ReturnType<typeof assignableWindow.setTimeout> { | ||
return getNativeImplementation('setTimeout')(...rest) as unknown as ReturnType<typeof assignableWindow.setTimeout> | ||
} |
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