Reputation: 1975
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.
Upvotes: 15
Views: 20274
Reputation: 861
I also got this error and I know that I can solve this issue using forwardRef()
but I didn't know where exactly I can put forwardRef()
.
Actually, the nestjs error shows where I have to put forwardRef()
. Let's have a look at the following error:
Error: Nest cannot create the AuthModule instance.
The module at index [3] of the AuthModule "imports" array is undefined.
My auth.module.ts
@Module({
imports: [
OccasionModule,
forwardRef(() => OrderModule),
BalanceModule,
UserModule,
PassportModule,
ReferralModule,
RoleModule,
JwtModule.register({
secret: jwtSecret,
}),
MongooseModule.forFeature([{
name: OTP.name,
schema: OTPSchema
}]),
],
providers: [
AuthService,
LocalStrategy,
],
controllers: [AuthController],
exports: [
AuthService
],
})
In my case module at index [3] of the AuthModule "imports" array
is UserModule
so I have to use forwardRef()
there and my auth.module.ts
will become:
@Module({
imports: [
OccasionModule,
forwardRef(() => OrderModule),
BalanceModule,
forwardRef(() => UserModule),
PassportModule,
ReferralModule,
RoleModule,
JwtModule.register({
secret: jwtSecret,
}),
MongooseModule.forFeature([{
name: OTP.name,
schema: OTPSchema
}]),
],
providers: [
AuthService,
LocalStrategy,
],
controllers: [AuthController],
exports: [
AuthService
],
})
export class AuthModule { }
Also don't forget to change
private userService:
UserService,
to
@Inject(forwardRef(() =>
UserService
))
private userService:
UserService,
in the auth.service.ts
.
After doing this you might get another dependency issue but with a different [index] of another Module. If you keep repeating the above process to add forwardRef()
then you will eventually solve the circular dependency issue.
But it's not good to have too many circular dependencies. It's better to design modules of your project in such a way that you get minimum possible or no circular dependency.
Upvotes: 0
Reputation: 1136
My issue was a silly one.
I had an extra comma in the Providers array of the module which I assume caused Nest to try and resolve and nonexisting provider. Removing the comma fixed it.
Upvotes: 3
Reputation: 6554
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.
And two supporting modules
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.
Upvotes: 25