angular
angular copied to clipboard
Please report about circular dependencies of standalone components on "build" step
Which @angular/* package(s) are relevant/related to the feature request?
compiler
Description
If standalone component A imports standalone component B, and B imports A, then ReferenceError: Cannot access 'A' before initialization
will be raised.
But it will be only raised in runtime 🤷♂️
Proposed solution
Please do not allow to compile components with circular dependencies.
Alternatives considered
Or, allow circular dependencies 😜
This is something that can be fixed (DX part) by the language service, that can import the component directly using the forwardRef().
Not every IDE uses language service. It would be nice to get an error from a compiler on the compilation step. But a preliminary warning from language service - that would be a great addition, of course.
There was the same error. The problem was using the static service method in the pipe. There was no circular dependency. The error indicated the module in which the pipe was declared
@e-oz it sounds like it is might not be directly linked to circular dependencies between files, but rather "typical" JS / TS situation with accessing classes before their initialisation.
It is surprising since our assumption was that TS would catch it: https://www.typescriptlang.org/play?target=2#code/JYWwDg9gTgLgBAbwMIXBAdgU3TAvnAMylTgHIABAQ3QHMBXAG0qgHoBjaTUgbgChfyKNFhwAKBLzhwYmcExkAuMqQA0kuKEiwAzkoDaAIQC6a3AEpebJtu1wAgolz8rlG3AOPeQA
Would you mind sharing the exact scenario when you were bumping into this error?
@pkozlowski-opensource it's a feature request, what reproduction? ;)
Here it is: https://stackblitz.com/edit/angular-ivy-vhsjhg?file=src/app/example/some-test.component.ts
Please open console and try to remove tag <some-example/>
from template.
I'm not sure if your assumption is correct, because this issue can be resolved by usage of forwardRef() (thanks to @eneajaho for finding this solution), and everything works when tag is not in the template.
Thnx for the reproduction @e-oz ! The interesting bit is that the error in a stackblitz is a different from the one you've initially reported. Just trying to make sure that the stackblitz scenario is the one you've seen initially.
@pkozlowski-opensource yes, I'm pretty sure now. I was trying to reproduce that exact error message, then I created a repo from StackBlitz code and found that I can't just run it locally - file tsconfig.app.json is missing, but StackBlitz builder still can build it - looks like it is the source of the error message difference.
https://github.com/e-oz/angular-ivy-vhsjhg
When I created tsconfig.app.json, I got that exact error message:
got the same problem migrating from ngModules, before all worked well and now it complains about circular dependency, forwardRef() solves it tho...
I've been struggling with this issue for the last 24h. It's so hard to debug. What is the fix? How can I detect the circular dependency? Is there an example with forwardRef I can follow?
@mparpaillon Example of forwardRef usage in this case:
@Component({
// ...
imports: [
CommonModule,
forwardRef(() => ExampleComponent)
],
// ...
})
@pkozlowski-opensource TS doesn't pick the issue when the classes are in a different file and the exception is raised when the circularity is expressed the in templates.
@mparpaillon replace one import in the circularity for example imports: [FooComponent]
by imports:[forwardRef(() => FooComponent)]
Thanks a lot. At this point I just don't know which components are causing the issue. In a big codebase that's very time consuming to find them. The error is thrown next to the lazy loaded module in the routing but doesn't tell me which component is causing it. Any tip for that?
@mparpaillon In devmode the error should be quite explicit which component throws and which component isn't available yet.
I guess I'm missing something then
layout.module.ts:77 is just a lazy loaded route (see below)
EDIT: I fixed my issue but the bug was quite specific with my codebase. Long story short I have "stores" (providers) that allows me to prevent too much props drilling (kinda like scoped global variables). Anyway, I managed to fix my issued by using inject() instead of standard constructor dependency injection.