Nx: How to resolve "Circular dependency" in NRWL

Created on 27 Feb 2020  路  23Comments  路  Source: nrwl/nx

I am getting the below LINT error

"Circular dependency between "A(lib)" and "B(lib)" detected (nx-enforce-module-boundaries) tslint error"
Most of the issues are coming when a Service from one Library is used(imported) in another lib.

Can you please help how to resolve this issue

more info needed misc question / discussion

Most helpful comment

There's also the issue when using something like typeorm. Database entities naturally can have circular dependencies where one entity has a OneToMany relation to another entity which itself has a ManyToOne relation to the prior entity. This causes a circular dependency which then causes errors. :/ Is there any way to solve this?

All 23 comments

U can't doing something like:
`
//LIB A
import libB from 'LIB_B'

//LIB B
import libA from 'LIB_A'
`
You create service "LIB_C" Which has methods that u used in LIB_A and LIB_B. LIB_C must be independent of LIB_A or LIB_B

Thanks, Yeah I am using in the same way, I have created a service 'LIB_XYZ which has the methods and I am using in other libraries, but still getting an error

If you use nx dep-graph you should be able to see the circular dependency.

What @czaplej mentioned about creating a 3rd library works a lot of the time.

I wrote an initial doc in the wiki on resolving circular dependencies:

https://github.com/nrwl/nx/wiki/Resolving-Circular-Dependencies

Let me know if it helps.

Anyway, something happened that NX started posting linter errors? I didn't change anything in my project, "only" updated from 8 to 9 and linter started throwing circular dep errors (same nx-enforce-module-boundaries settings).

I have similar errors that @kkuriata said. I have use 9.0.4 version of nx

I think @kkuriata is right. I'm also seeing the circular dependency issues after upgrading to 9.

Thanks, Yeah I am using in the same way, I have created a service 'LIB_XYZ which has the methods and I am using in other libraries, but still getting an error

I have manually updated the code by removing which has a circular dependency, It works fine now, Actually, all libraries are interrelated, so if one has dependency most of the other related are also failing

I getting false positives of nx-enforce-module-boundaries

I have this graph

image

Where each of the akita-ng-libraries have akita as a peerDependency

I also have a demo app which uses all of the above (remember peerDependencies) which causes the graph to look like this

image

and now I'm getting spammed with false nx-enforce-module-boundaries

Circular dependency between "akita-ng-entity-service" and "akita" detected
Circular dependency between "akita-ng-forms-manager" and "akita" detected
etc

please advice

Nevermind, I missed the arrow going from akita to the app :/

Now I'm not getting any nx-enforce-module-boundaries

image

Pretty cool tool - I must say

I'm facing difficulties understanding how to best structure my NX workspace in apps and libs to optimize build times and benefit from caching, considering an Angular + NGRX app.

As the starting point, I had one "web" app, composed of many major "features", each with its own (lazy-loaded) Angular module. Those modules were loaded lazily through the router, but also eagerly when a dependent Angular module needed it (e.g., if module X needs module Y, it has it in its imports).

As part of my current refactoring, I've extracted most of those features in separate libraries: one per major feature of the app, which I load lazily when needed.

Now, after fixing compilation issues, I remain with circular dependencies. My question is: what is your experience with splitting inter-dependent lazy-loaded Angular modules and what would be your recommendation?

Do you recommend splitting each feature in multiple libs (e.g., feature-x-core, feature-x-store, feature-x-dumb-components, feature-x-smart-components, ...)?

I've given this some thought and I don't see a clear path forward. For instance, if I consider the NGRX selectors of feature-x, then I can see that those rely on state types and selectors from feature-y.

One idea that I still have is extracting some parts (e.g., reducers & selectors) of the store for each feature and putting those in a shared "core" lib, but I'd still remain with the Angular module imports. Or should I just ignore the lint error in that case?

In our case I feel like keeping all of those features in the same NX lib is detrimental as it represents > 80% of the whole app.

Hi difficult to find why I have circular dependency! don't see any dependency from core -> webapp in the code
https://github.com/xmlking/yeti

image

@xmlking
image

something happened that NX started posting linter errors? I didn't change anything in my project, "only" updated from 8 to 9 and linter started throwing circular dep errors

Yes, Nx is able to resolve more dependencies in 9 than before in 8. As a result, a dependency could have been resolved that now causes a circular dependency. These are valid dependencies.

For example,

Relative dependencies are now a resolved dependency even though they are not recommended.

import { } from '../../libs/libA/src'; // Is now a dependency

I'm going to close this issue as I've started a guide.

https://github.com/nrwl/nx/wiki/Resolving-Circular-Dependencies

Please open a new issue if that guide does not cover a method for resolving circular dependencies so we can add it.

@FrozenPandaz
I'm currently having a situation where i'm using the environment.ts file from my app into more than one library and those libraries are used in this app . which was going fine with angular 8 , but now it's showing a circular dep error . Is there a way to get a round that ?

in my tsconfig.json file i have this code added to paths
"@global-env/*": ["apps/web/src/environments/*"],

i have a library called core-data-access where i call the environment
import { environment } from '@global-env/environment';

then i import some services from the core-data-access library in my web app

2851

@Abdallah-khalil You should move your environment files into some common library that will be imported by all the apps you need. You can then use fileReplacements in angular.json/workspace.json to replace specific environment for chosen build. Unfortunately when you want to use fileReplacements with default dev build (ng serve), then you need to point the configuration: ng serve --configuration=serve (@FrozenPandaz not sure if it is a bug or it is inteded).

For example, when I have two projects: project1 and project2. And one lib core.

libs/core
  /environments
    /project1
      environment.serve.ts
      environment.prod.ts
    /project2
      environment.serve.ts
      environment.prod.ts
  environment.ts // this one will be replaced by any from above

Then I use angular.json to set file replacements inside serve configuration to have it by default when I develop new features. Unfortunately in this case it is not enough as I mentioned. Even when I specify file replacement for both projects, it won't work without --configuration=serve flag. But because serve is default ng serve configuration, hence I think it is a bug, but not sure.

There's also the issue when using something like typeorm. Database entities naturally can have circular dependencies where one entity has a OneToMany relation to another entity which itself has a ManyToOne relation to the prior entity. This causes a circular dependency which then causes errors. :/ Is there any way to solve this?

I updated the nx workspace recently, and I'm no longer seeing the circular dep errors. Can someone from nx team confirm if this is fixed or still a known issue?

@Ponjimon That's a very good point, and one that is keeping me (wrongly or rightly) from having multiple modules for my TypeORM entities.

Another possible scenario, which I have encountered, is when using NgRX Router Store, like in https://blog.nrwl.io/using-ngrx-4-to-manage-state-in-angular-applications-64e7a1f84b7b

E.g.
2 libs, a UI lib and a store lib.
you set up effects in the store lib to respond to navigation to a component in the UI lib.
a component in the UI lib calls the store facade to retrieve some data that it needs.

Thus a circular dependency.
In Victor's post the components which are the subject of navigation are in the same app as the effects, etc, as it is a simple example.

Another possible scenario, which I have encountered, is when using NgRX Router Store, like in https://blog.nrwl.io/using-ngrx-4-to-manage-state-in-angular-applications-64e7a1f84b7b

E.g.
2 libs, a UI lib and a store lib.
you set up effects in the store lib to respond to navigation to a component in the UI lib.
a component in the UI lib calls the store facade to retrieve some data that it needs.

Thus a circular dependency.
In Victor's post the components which are the subject of navigation are in the same app as the effects, etc, as it is a simple example.

I have run into this exact situation! Slightly less complex however.

I am using a lib that container my auth store, its being used in the login feature lib. I want to use the navigated helper to generate a cookie when the login component is loaded however this is a direct circular dependancy.

I see no way around this.... that is if i am going to the navigated helper.....

so it sounds like some of these circular dependencies are just saying

HE... he is using some stuff from HER
and
HER is using some stuff from HE

but as long as it executes fine there should be no problem

unless these circular dependencies are warning of an infinite loop?

I think the definition of circular dependency needs to be revisited

maybe these are just BIDIRECTIONAL ASSOCIATIONS which may be harmless

and a REAL circular dependency means INFINITE LOOP imminent

any thoughts ?

can someone elaborate simply confirming somethings I noted here ?
because the alternative to resolve all these means proliferated libs
and for large scale project this could ensue as CHAOS where everything needs to be a library
and what ensues when some library needs multiple pieces of logic already isolated in multiple libraries?

Adding to what @ghost said, it seems that a circular dependency is unavoidable when using the navigation operator in an effect, if the component that the operator references is not in the same module (or lib) as the effect.

In my case, the component communicates exclusively with a facade in a data access lib to get its data. But after switching my effect to use the router as the source of truth as recommended in the article previously cited, the effect in the the data access lib references back to the component in the ui lib. Guaranteed circular dependency. Splitting apart data access libs from ui libs isn't an anti-pattern, but perhaps there is some nuance I'm not appreciating.

Any insights or best practices are welcome. Thanks.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MichaelWarneke picture MichaelWarneke  路  3Comments

joelmuskwe picture joelmuskwe  路  3Comments

elliotmendiola picture elliotmendiola  路  3Comments

dereklin picture dereklin  路  3Comments

Svancara picture Svancara  路  3Comments