Issue with assigning lazy loaded standalone components environment injectors
Which @angular/* package(s) are the source of the bug?
router
Is this a regression?
No
Description
Noticed some odd DI/Router behaviour,
I have 2 lazily loaded standalone components, each loading from different routes, each importing an NgModule that provides a service.
Source here https://stackblitz.com/edit/angular-n7t8rb, you may have to visit this first to get the links below working.
If I visit https://angular-n7t8rb.stackblitz.io/ and then click the “lazy two” button, I get a DI error. If i visit https://angular-n7t8rb.stackblitz.io/two it loads successfully. Why would this work when the router-based navigation above did not? When i click the “lazy one” button to load the other lazy component, theres a DI error.
I’ve logged the injectors created by each component as they render, it looks like the first Lazy component that gets loaded is the one that gets a new Environment Injector, the second does not, causing the DI error. We get an R3 injector for App and 1 for either LazyComponent or LazyTwoComponent, based on which loads first. I think this is related to the usage of loadComponent
I made another example with loadChildren for one route and loadComponent for the second, https://stackblitz.com/edit/angular-3ffdoh. In this case we get no errors and an R3 injector for App, LazyComponent and LazyTwoComponent, which seems to me like the expected behavior.
I've created a minimal reproduction that doesn't use lazy-loaded components or the router here: https://stackblitz.com/edit/angular-extdt1?file=src%2Fmain.ts
The issue is that your components have the same selector. I'm not sure why this causes this behavior (edit: see my comment below for why), but you can see the NG0912 warning (https://angular.io/errors/NG0912) in the console.
The issue goes away if you fix the duplicate component id issue in any of the ways described by the NG0912 docs.
I think the root cause is that standalone component injectors are cached by their component id here: https://github.com/angular/angular/blob/4550fe42f704b18f48bd0c490b0c6a283ea912c5/packages/core/src/render3/features/standalone_feature.ts#L26-L41
This explains why the order of component activation matters for your reproduction. When the second component is created, it's pulling the injector from the cache instead of creating a new one like you'd expect.
Thnx for digging into it @garrettld - this raises an interesting question of using component's id as a key in the cachedInjectors - it seems like it is not reliable enough.
Related: #46093 and #50158
this raises an interesting question of using component's id as a key in the cachedInjectors - it seems like it is not reliable enough.
@pkozlowski-opensource agreed, the component ids that we generate based on the metadata may have collisions. We plan to improve their generation further (by using more fields, including styles), but we should transition to something else (probably a WeakMap) in the DI code to always have proper component->injector connection. // cc @alan-agius4
This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.