Skip to content

Commit

Permalink
fix(core): get root and platform injector providers in special cases (#…
Browse files Browse the repository at this point in the history
…52365)

Previously, because the platform injector does not have a provider container, this API would fail. Now, we account for this case specifically by returning the found providers immediately, without trying to calculate their importpaths.

Also previously, in the case where a boostrapped standalone component did not import any feature modules, the environment injector connected to that bootstrapped component would be the root injector configured by `bootstrapApplication`. This injector is configured through a `providers` array instead of an `imports` array, and also does not have a provider container. Similarly to the platform case, we account this for this by returning the found providers immediately if there is no provider container for our standalone component.

PR Close #52365
  • Loading branch information
AleksanderBodurri authored and dylhunn committed Oct 25, 2023
1 parent ea6d752 commit 957effa
Showing 1 changed file with 31 additions and 1 deletion.
32 changes: 31 additions & 1 deletion packages/core/src/render3/util/injector_discovery_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ function getProviderImportsContainer(injector: Injector): Type<unknown>|null {
return null;
}

// In standalone applications, the root environment injector created by bootstrapApplication
// may have no associated "instance".
if (defTypeRef.instance === null) {
return null;
}

return defTypeRef.instance.constructor;
}

Expand Down Expand Up @@ -386,13 +392,29 @@ function walkProviderTreeToDiscoverImportPaths(
* @returns an array of objects representing the providers of the given injector
*/
function getEnvironmentInjectorProviders(injector: EnvironmentInjector): ProviderRecord[] {
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];

// platform injector has no provider imports container so can we skip trying to
// find import paths
if (isPlatformInjector(injector)) {
return providerRecords;
}

const providerImportsContainer = getProviderImportsContainer(injector);
if (providerImportsContainer === null) {
// There is a special case where the bootstrapped component does not
// import any NgModules. In this case the environment injector connected to
// that component is the root injector, which does not have a provider imports
// container (and thus no concept of module import paths). Therefore we simply
// return the provider records as is.
if (isRootInjector(injector)) {
return providerRecords;
}

throwError('Could not determine where injector providers were configured.');
}

const providerToPath = getProviderImportPaths(providerImportsContainer);
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];

return providerRecords.map(providerRecord => {
let importPath = providerToPath.get(providerRecord.provider) ?? [providerImportsContainer];
Expand All @@ -409,6 +431,14 @@ function getEnvironmentInjectorProviders(injector: EnvironmentInjector): Provide
});
}

function isPlatformInjector(injector: Injector) {
return injector instanceof R3Injector && injector.scopes.has('platform');
}

function isRootInjector(injector: Injector) {
return injector instanceof R3Injector && injector.scopes.has('root');
}

/**
* Gets the providers configured on an injector.
*
Expand Down

0 comments on commit 957effa

Please sign in to comment.