15

What is the correct way to import dynamic modules when there's a circular dependency between them? I simply changed forwardRef(() => MyModule) to forwardRef(() => MyModule.forRoot()), and I'm getting Nest can't resolve dependencies error.

frederj
  • 1,483
  • 9
  • 20
dols3m
  • 1,676
  • 2
  • 16
  • 25
  • Could you share your module definitions please. Also, if you can avoid circular it’s better some times you can’t but otherwise its an architectural issue – Adrien De Peretti Jun 03 '19 at 18:59

1 Answers1

24

The best way to deal with nest module dependency is to import dependencies always through modules and never through services. If you run into a circular dependency, nest will show you an error and you can easily fix it with forwardRef().

let say your application has 3 tightly coupled modules.

  • @moduleA()
  • @moduleB()
  • @moduleC()

And two supporting modules

  • @moduleX()
  • @moduleY()
  • @moduleZ()

Also, all modules are exporting services with the same name.

Consider a situation where

@moduleA() imports [serviceB, serviceX]

And

@moduleB() imports [serviceA, serviceY, serviceZ]

Now in @moduleC() if you want to use serivceA() then you will have to

@moduleC() imports [serviceA, serviceB, serviceX, serviceY, serviceZ]

In most cases, nest throws the correct error saying which dependency is missing where. But some times, nest only says dependency at [index] is missing, nest doesn't says where it is missing. This will lead to great level of confusion.

A neat approach is to always import modules

@moduleA() imports [moduleB, moduleX]

@moduleB() imports [moduleA, moduleY, moduleZ]

@moduleC() imports [moduleA]


If nest is complaining again about dependency issue then import modules using forwardRef

@module({
     imports: [
       forwardRef(() => ModuleA)
       ModuleB
       ],
    controllers: [],
    providers: []
})

Sometimes even after doing all these, you may again run into dependency not available error. Then you can use ModuleRef. Let's take the same example where you want to use ServiceA() in ModuleC()

You will then be adding serviceA() to providers[] in ModuleC() and in the serviceC() class you need to add the following.

import { Injectable, OnModuleInit } from '@nestjs/common'; \\need OnModuleInit 
import { ServiceA} from '../FolderA/serviceA.service';

export class ServiceC implements OnModuleInit {
   
   private serviceA: ServiceA;
   constructor(private readonly moduleRef: ModuleRef) {}

   onModuleInit() {
        this.serviceA= this.moduleRef.get(ServiceA);
    }
   
   foo(){
     console.log(this.serviceA.someFunction())
   }
}

Please check more at Official documentation.

Community
  • 1
  • 1
Anees Hameed
  • 5,916
  • 1
  • 39
  • 43
  • 2
    If anyone is certain they don't have circular dependencies, but still get this error message, pay close attention to your `imports` property in `*.module.ts`. I found that having two commas, like `,,` causes this error. – Alec Branaa Jul 17 '20 at 19:12
  • Your solution is awesome , sir. But in my case, I need to pass { strict: false } option as a second argument to get(). Hope this can help someone ^^ – ninoorta Jan 21 '22 at 02:01
  • 1
    Similarly as Alec pointed out, I didn't have circular dependencies among the the services, etc, but I had a constant defined in the module.ts that I imported in one of the services. Took me quite some time to understand the cause. – matiss.andersons Oct 23 '22 at 15:42