diff --git a/packages/core/src/core_private_export.ts b/packages/core/src/core_private_export.ts index 9fd2a146ff3..f25e986438c 100644 --- a/packages/core/src/core_private_export.ts +++ b/packages/core/src/core_private_export.ts @@ -26,6 +26,7 @@ export {ReflectionCapabilities as ɵReflectionCapabilities} from './reflection/r export {allowSanitizationBypassAndThrow as ɵallowSanitizationBypassAndThrow, BypassType as ɵBypassType, getSanitizationBypassType as ɵgetSanitizationBypassType, SafeHtml as ɵSafeHtml, SafeResourceUrl as ɵSafeResourceUrl, SafeScript as ɵSafeScript, SafeStyle as ɵSafeStyle, SafeUrl as ɵSafeUrl, SafeValue as ɵSafeValue, unwrapSafeValue as ɵunwrapSafeValue} from './sanitization/bypass'; export {_sanitizeHtml as ɵ_sanitizeHtml} from './sanitization/html_sanitizer'; export {_sanitizeUrl as ɵ_sanitizeUrl} from './sanitization/url_sanitizer'; +export {setAlternateWeakRefImpl as ɵsetAlternateWeakRefImpl} from './signals'; export {TESTABILITY as ɵTESTABILITY, TESTABILITY_GETTER as ɵTESTABILITY_GETTER} from './testability/testability'; export {escapeTransferStateContent as ɵescapeTransferStateContent, makeStateKey as ɵmakeStateKey, StateKey as ɵStateKey, TransferState as ɵTransferState, unescapeTransferStateContent as ɵunescapeTransferStateContent} from './transfer_state'; export {coerceToBoolean as ɵcoerceToBoolean} from './util/coercion'; diff --git a/packages/core/src/signals/index.ts b/packages/core/src/signals/index.ts index 0bce60ccd75..fea23d465df 100644 --- a/packages/core/src/signals/index.ts +++ b/packages/core/src/signals/index.ts @@ -13,3 +13,4 @@ export {setActiveConsumer} from './src/graph'; export {SettableSignal, signal} from './src/signal'; export {untracked} from './src/untracked'; export {Watch} from './src/watch'; +export {setAlternateWeakRefImpl} from './src/weak_ref'; diff --git a/packages/core/src/signals/src/computed.ts b/packages/core/src/signals/src/computed.ts index 0062e896297..15ae255492d 100644 --- a/packages/core/src/signals/src/computed.ts +++ b/packages/core/src/signals/src/computed.ts @@ -8,7 +8,7 @@ import {createSignalFromFunction, defaultEquals, Signal, ValueEqualityFn} from './api'; import {Consumer, ConsumerId, consumerPollValueStatus, Edge, nextReactiveId, Producer, producerAccessed, ProducerId, producerNotifyConsumers, setActiveConsumer} from './graph'; -import {WeakRef} from './weak_ref'; +import {newWeakRef} from './weak_ref'; /** * Create a computed `Signal` which derives a reactive value from an expression. @@ -70,7 +70,7 @@ class ComputedImpl implements Producer, Consumer { private stale = true; readonly id = nextReactiveId(); - readonly ref = new WeakRef(this); + readonly ref = newWeakRef(this); readonly producers = new Map(); readonly consumers = new Map(); trackingVersion = 0; diff --git a/packages/core/src/signals/src/signal.ts b/packages/core/src/signals/src/signal.ts index 4b44a6a8718..a1726e134a3 100644 --- a/packages/core/src/signals/src/signal.ts +++ b/packages/core/src/signals/src/signal.ts @@ -8,7 +8,7 @@ import {createSignalFromFunction, defaultEquals, Signal, ValueEqualityFn} from './api'; import {ConsumerId, Edge, nextReactiveId, Producer, producerAccessed, producerNotifyConsumers} from './graph'; -import {WeakRef} from './weak_ref'; +import {newWeakRef, WeakRef} from './weak_ref'; /** * A `Signal` with a value that can be mutated via a setter interface. @@ -41,7 +41,7 @@ class SettableSignalImpl implements Producer { constructor(private value: T, private equal: ValueEqualityFn) {} readonly id = nextReactiveId(); - readonly ref = new WeakRef(this); + readonly ref = newWeakRef(this); readonly consumers = new Map(); valueVersion = 0; diff --git a/packages/core/src/signals/src/watch.ts b/packages/core/src/signals/src/watch.ts index ba96d6c917c..60931aa5589 100644 --- a/packages/core/src/signals/src/watch.ts +++ b/packages/core/src/signals/src/watch.ts @@ -7,7 +7,7 @@ */ import {Consumer, consumerPollValueStatus, Edge, nextReactiveId, ProducerId, setActiveConsumer} from './graph'; -import {WeakRef} from './weak_ref'; +import {newWeakRef} from './weak_ref'; /** * Watches a reactive expression and allows it to be scheduled to re-run @@ -18,7 +18,7 @@ import {WeakRef} from './weak_ref'; */ export class Watch implements Consumer { readonly id = nextReactiveId(); - readonly ref = new WeakRef(this); + readonly ref = newWeakRef(this); readonly producers = new Map(); trackingVersion = 0; diff --git a/packages/core/src/signals/src/weak_ref.ts b/packages/core/src/signals/src/weak_ref.ts index 53587229f29..6e045010914 100644 --- a/packages/core/src/signals/src/weak_ref.ts +++ b/packages/core/src/signals/src/weak_ref.ts @@ -9,15 +9,30 @@ import {global} from '../../util/global'; // `WeakRef` is not always defined in every TS environment where Angular is compiled. Instead, -// alias it as a local export by reading it off of the global context. +// read it off of the global context if available. +// tslint:disable-next-line: no-toplevel-property-access +let WeakRefImpl: WeakRefCtor|undefined = global['WeakRef']; export interface WeakRef { deref(): T|undefined; } +export function newWeakRef(value: T): WeakRef { + if (typeof ngDevMode !== 'undefined' && ngDevMode && WeakRefImpl === undefined) { + throw new Error(`Angular requires a browser which supports the 'WeakRef' API`); + } + return new WeakRefImpl!(value); +} + export interface WeakRefCtor { new(value: T): WeakRef; } -// tslint:disable-next-line: no-toplevel-property-access -export const WeakRef: WeakRefCtor = global['WeakRef']; +/** + * Use an alternate implementation of `WeakRef` if a platform implementation isn't available. + */ +export function setAlternateWeakRefImpl(impl: WeakRefCtor) { + if (!WeakRefImpl) { + WeakRefImpl = impl; + } +}