diff --git a/packages/core/src/render3/debug/framework_injector_profiler.ts b/packages/core/src/render3/debug/framework_injector_profiler.ts index d5253741bf8cb..b99e81e9a9b7e 100644 --- a/packages/core/src/render3/debug/framework_injector_profiler.ts +++ b/packages/core/src/render3/debug/framework_injector_profiler.ts @@ -6,11 +6,12 @@ * found in the LICENSE file at https://angular.io/license */ +import {InjectionToken} from '../../di'; import {Injector} from '../../di/injector'; import {EnvironmentInjector} from '../../di/r3_injector'; import {Type} from '../../interface/type'; import {assertDefined, throwError} from '../../util/assert'; -import {assertTNode, assertTNodeForLView} from '../assert'; +import {assertTNodeForLView} from '../assert'; import {getComponentDef} from '../definition'; import {getNodeInjectorLView, getNodeInjectorTNode, NodeInjector} from '../di'; import {TNode} from '../interfaces/node'; @@ -54,16 +55,15 @@ import {InjectedService, InjectorCreatedInstance, InjectorProfilerContext, Injec * */ class DIDebugData { - resolverToTokenToDependencies = - new WeakMap, InjectedService[]>>(); - resolverToProviders = new WeakMap(); + resolverToTokenToDependencies = new WeakMap< + Injector|LView, WeakMap|InjectionToken, WeakRef>>(); + resolverToProviders = new WeakMap>(); standaloneInjectorToComponent = new WeakMap>(); reset() { - this.resolverToTokenToDependencies = - new WeakMap, InjectedService[]>>(); - this.resolverToProviders = new WeakMap(); - this.standaloneInjectorToComponent = new WeakMap>(); + this.resolverToTokenToDependencies = new WeakMap(); + this.resolverToProviders = new WeakMap(); + this.standaloneInjectorToComponent = new WeakMap(); } } @@ -121,7 +121,7 @@ function handleInjectEvent(context: InjectorProfilerContext, data: InjectedServi const diResolverToInstantiatedToken = frameworkDIDebugData.resolverToTokenToDependencies; if (!diResolverToInstantiatedToken.has(diResolver)) { - diResolverToInstantiatedToken.set(diResolver, new WeakMap, InjectedService[]>()); + diResolverToInstantiatedToken.set(diResolver, new WeakMap()); } // if token is a primitive type, ignore this event. We do this because we cannot keep track of @@ -131,17 +131,15 @@ function handleInjectEvent(context: InjectorProfilerContext, data: InjectedServi } const instantiatedTokenToDependencies = diResolverToInstantiatedToken.get(diResolver)!; - if (!instantiatedTokenToDependencies.has(context.token!)) { - instantiatedTokenToDependencies.set(context.token!, []); - } - - const {token, value, flags} = data; - assertDefined(context.token, 'Injector profiler context token is undefined.'); - const dependencies = instantiatedTokenToDependencies.get(context.token); - assertDefined(dependencies, 'Could not resolve dependencies for token.'); + let dependencies = instantiatedTokenToDependencies.get(context.token)?.deref(); + if (!dependencies) { + dependencies = []; + instantiatedTokenToDependencies.set(context.token, new WeakRef(dependencies)); + } + const {token, value, flags} = data; if (context.injector instanceof NodeInjector) { dependencies.push({token, value, flags, injectedIn: getNodeInjectorContext(context.injector)}); } else { @@ -251,11 +249,13 @@ function handleProviderConfiguredEvent( throwError('A ProviderConfigured event must be run within an injection context.'); } - if (!resolverToProviders.has(diResolver)) { - resolverToProviders.set(diResolver, []); + let resolverData = resolverToProviders.get(diResolver)?.deref(); + if (!resolverData) { + resolverData = []; + resolverToProviders.set(diResolver, new WeakRef(resolverData)); } - resolverToProviders.get(diResolver)!.push(data); + resolverData.push(data); } function getDIResolver(injector: Injector|undefined): Injector|LView|null { diff --git a/packages/core/src/render3/util/global_utils.ts b/packages/core/src/render3/util/global_utils.ts index e96704672b873..8fe60a3b8ca4c 100644 --- a/packages/core/src/render3/util/global_utils.ts +++ b/packages/core/src/render3/util/global_utils.ts @@ -71,8 +71,9 @@ export function publishDefaultGlobalUtils() { if (!_published) { _published = true; - if (typeof window !== 'undefined') { - // Only configure the injector profiler when running in the browser. + // Only configure the injector profiler when running in the browser and WeakRef is defined. + // In some G3 tests WeakRef is undefined as they user older (unsupported) browsers to test. + if (typeof window !== 'undefined' && typeof WeakRef !== 'undefined') { setupFrameworkInjectorProfiler(); } diff --git a/packages/core/src/render3/util/injector_discovery_utils.ts b/packages/core/src/render3/util/injector_discovery_utils.ts index 136937dd28a2b..6a952a328ccb3 100644 --- a/packages/core/src/render3/util/injector_discovery_utils.ts +++ b/packages/core/src/render3/util/injector_discovery_utils.ts @@ -132,12 +132,12 @@ function getDependenciesForTokenInInjector( const {resolverToTokenToDependencies} = getFrameworkDIDebugData(); if (!(injector instanceof NodeInjector)) { - return resolverToTokenToDependencies.get(injector)?.get?.(token as Type) ?? []; + return resolverToTokenToDependencies.get(injector)?.get?.(token)?.deref() ?? []; } const lView = getNodeInjectorLView(injector); const tokenDependencyMap = resolverToTokenToDependencies.get(lView); - const dependencies = tokenDependencyMap?.get(token as Type) ?? []; + const dependencies = tokenDependencyMap?.get(token)?.deref() ?? []; // In the NodeInjector case, all injections for every node are stored in the same lView. // We use the injectedIn field of the dependency to filter out the dependencies that @@ -207,7 +207,8 @@ function getProviderImportsContainer(injector: Injector): Type|null { function getNodeInjectorProviders(injector: NodeInjector): ProviderRecord[] { const diResolver = getNodeInjectorTNode(injector); const {resolverToProviders} = getFrameworkDIDebugData(); - return resolverToProviders.get(diResolver as TNode) ?? []; + + return resolverToProviders.get(diResolver as TNode)?.deref() ?? []; } /** @@ -395,7 +396,7 @@ function walkProviderTreeToDiscoverImportPaths( */ function getEnvironmentInjectorProviders(injector: EnvironmentInjector): ProviderRecord[] { const providerRecordsWithoutImportPaths = - getFrameworkDIDebugData().resolverToProviders.get(injector) ?? []; + getFrameworkDIDebugData().resolverToProviders.get(injector)?.deref() ?? []; // platform injector has no provider imports container so can we skip trying to // find import paths diff --git a/packages/tsconfig-build.json b/packages/tsconfig-build.json index 7356a0575365d..95a9d7f65e2ee 100644 --- a/packages/tsconfig-build.json +++ b/packages/tsconfig-build.json @@ -21,7 +21,7 @@ "target": "es2022", // Keep the below in sync with ng_module.bzl "useDefineForClassFields": false, - "lib": ["es2020", "dom", "dom.iterable"], + "lib": ["es2020", "dom", "dom.iterable", "ES2021.WeakRef"], "skipLibCheck": true, // don't auto-discover @types/node, it results in a ///