Dealing with circular dependencies
How to deal with the most common examples of circular dependencies
This lesson preview is part of the Next-Level Angular Apps with NX course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Next-Level Angular Apps with NX, plus 70+ \newline books, guides and courses with the \newline Pro subscription.

[00:00 - 00:11] In this lesson, you will learn what circular dependencies are, how to create them, and what's more important, how to fix them. Circular dependency happens when you have a cycle on the dependency graph.
[00:12 - 00:20] So, let's consider that you have two libraries. To build library one, you need to import component two from library two.
[00:21 - 00:28] And to build library two, you have to import component one from library one. And you have that strange loop.
[00:29 - 00:40] You cannot build library one without library two, and you cannot build library two without library one. And circular dependencies are a popular problem, not only in NX, but in front of the adults.
[00:41 - 00:49] Luckily, we have methods of solving them, and in this lesson, you learn about two of them. It's worth mentioning that more than two libraries can't create a cycle.
[00:50 - 01:01] In fact, there is no limit of number of libraries taking part in cycle. What is important that every time you have that strange loop on the graph.
[01:02 - 01:09] So, let's create some circular dependencies. I'm going to start by creating a new NX monorepo.
[01:10 - 01:16] Then I will add necessary dependencies for NX Angular. I will generate a new app and two libraries.
[01:17 - 01:24] First library will be called shared services. So, the difference is that the library will contain a service that will mock authentication.
[01:25 - 01:32] The second library will be called shared components. So, the difference is between services and components.
[01:33 - 01:45] And the second library will contain component called "of dialog". So, service will dynamically create a component, a dialog component, that will use the same service to close itself on close function.
[01:46 - 01:54] All the comments that I'm going to execute, you see on screen, we went through this multiple times. So, let me execute all the comments.
[01:55 - 02:00] I will clean up a little bit the monorepo, and then we will start adding some code. All right.
[02:01 - 02:11] So, everything was generated in my app's directory. I have my app, and in my leaps directory, I have two more libraries called components and services.
[02:12 - 02:22] And inside both of them, I have "of library". So, let's list "leaps shared components of".
[02:23 - 02:31] As you can see, it's just a standard library. Let me switch to the IDE, and I walk you through the code that generates a circular dependency.
[02:32 - 02:35] So, give me a second. Okay, code is done.
[02:36 - 02:44] Let's start with "leaps services of". And as you can see, I removed "generated code", and I have "of service.ts" file .
[02:45 - 02:49] So, "of service.ts" is a simple file. I have two methods.
[02:50 - 02:59] I have "open login dialog", that is using component factory resolver to create factory for "of dialog" component. And I have the second method.
[03:00 - 03:04] Code is not important here. We should only focus on dependencies between libraries.
[03:05 - 03:14] So, let's go to the "of dialog" component. As you can see, we have that red wave here, and it means that there is something wrong with that import.
[03:15 - 03:17] Let's go here. It's my second library.
[03:18 - 03:29] So, it's "leaps shared component of source sleep and of dialog component". And it's a simple component that is using "of service".
[03:30 - 03:46] So, we have a circular dependency between "shared components of" and "shared services out", because I'm using this method "close login dialog". The last part, in my app, in app component, I'm injecting that "of service" just to be sure that it's part of compilation.
[03:47 - 03:59] So, now we can go to our console, and we can type a build comment and check how it works. So, I have "yarn and xrun app build with configuration production".
[04:00 - 04:14] And as you can see, immediately, we have an error that says that "build command could not be executed", because there is a circular dependency. And you can even check the dependency chain that creates a cycle.
[04:15 - 04:25] So, we have "app build" to "shared services out" to "shared components out" and the "back to shared services out". And that's our cycle.
[04:26 - 04:34] How to solve a circular dependency problem? I promise you two methods today, so first one is merging libraries.
[04:35 - 05:01] If you merge two libraries, for example, "shared services out" and "shared components out", if you merge them, there is no circular dependency, because you have only one library that you import. And I know that it's not the perfect solution, like we very often don't want to merge libraries, we want to have it separated for, for any other channel reasons, we want to have smaller libraries.
[05:02 - 05:15] And you can even imagine if you will use merging libraries method to solve circular dependency problem, you will end with one huge library. To sum up, the biggest disadvantage of this method is that it's bad for code to decomposition.
[05:16 - 05:25] If you created two libraries, most often you want to have two libraries instead of one. So the second method is by splitting libraries.
[05:26 - 05:37] So you can take the problematic part and split it to the first library. And both "shared services out" and "shared components out" will depend on that one library.
[05:38 - 05:46] So there is no cycle. On the screen at the moment you have a simple graph printed, so we have our " shared services out" and "shared components out".
[05:47 - 05:54] That depends on "shared services out" close. And that's what we are going to use to solve our problem.
[05:55 - 06:09] So let me generate the third library called "shared services outflows". And we will move the close code to that part, because the close code is used in both "shared services out" and "shared components out".
[06:10 - 06:16] So I'm going to execute comments to generate a new library. I will refactor my code and I will show you the result.
[06:17 - 06:24] Let's start with our newly created library "outflows". So as you can see I have "outflows service.ts" file here.
[06:25 - 06:28] And it's a simple service. As I mentioned, don't focus on the code.
[06:29 - 06:34] Focus on dependencies between libraries. So this "outflow service" is injected in "out service".
[06:35 - 06:51] And I'm using that "outflow service" in "close login dialog" method. Then in "outflow" component instead of injecting "out service", the whole service that keeps all the important methods, I'm injecting only "outflow service".
[06:52 - 06:59] So our third newly created library. Both "out service" and "outflow" component depends on "outflow service".
[07:00 - 07:09] And if we go to the console and we will execute the build command as previously , as you can see everything works. Circular dependency has been solved.
[07:10 - 07:22] To sum up, circular dependency happens when you have a cycle on the dependency graph. And it's not only an annex problem, it happens in front and word all the time.
[07:23 - 07:27] We have two simple methods to fix the problem. You can merge libraries.
[07:28 - 07:35] So from two libraries you can create one bigger library. And it should not contain a cycle because it's only one library.
[07:36 - 07:43] Or you can split libraries, increase the composition, and break the dependency chain. And as you can see it's not a huge problem.
[07:44 - 07:48] But still, you need to solve it if you want to use NX.