nest: Can't resolve dependencies bug introduced with v6.3.1

Bug Report

Current behavior

With version 6.3.1 injecting a repository into a service is not working anymore.

 Nest can't resolve dependencies of the AuthenticationService (JwtService, ?, LogService, ConfigService). Please make sure that the argument at index [1] is available in the AuthenticationModule context. Error: Nest can't resolve dependencies of the AuthenticationService (JwtService, ?, LogService, ConfigService). Please make sure that the argument at index [1] is available in the AuthenticationModule context.
    at Injector.lookupComponentInExports (PROJECT_PATH/node_modules/@nestjs/core/injector/injector.js:180:19)
    at process._tickCallback (internal/process/next_tick.js:68:7)
    at Function.Module.runMain (internal/modules/cjs/loader.js:757:11)
    at Object.<anonymous> (PROJECT_PATH/node_modules/ts-node/src/bin.ts:157:12)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12) ExceptionHandler

Input Code

Authentication Service (Constructor)

export class AuthenticationService {
  constructor(
    private readonly jwtService: JwtService,
    @InjectRepository(Customer)
    private readonly customerRepository: Repository<Customer>,
    private readonly logger: LogService,
    private readonly config: ConfigService
  ) {}
}

Authentication Module

/**
 * Map Passport Module to a reusable variable
 */
const passportModule = PassportModule.register({defaultStrategy: 'jwt'});

@Global()
@Module({
  imports: [
    passportModule,
    JwtModule.registerAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        secret: config.get('JWT_SECRET_KEY')
      })
    }),
    CustomerModule
  ],
  providers: [AuthenticationService, AuthenticationResolver],
  exports: [passportModule, AuthenticationService]
})
export class AuthenticationModule {}

Customer Module

@Module({
  imports: [TypeOrmModule.forFeature([Customer]), MailModule, HttpModule],
  providers: [CustomerResolver, CustomerService]
})
export class CustomerModule {}

Expected behavior

The command ts-node -r tsconfig-paths/register src/main.ts should start the app without any errors.

Possible Solution

In v6.3.0 the build is still working so I guess the bug was introduced with v6.3.1

Environment


Nest version: 6.3.1

 
For Tooling issues:
- Node version: 10.15.3  
- Platform: Mac

Others:

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 37 (9 by maintainers)

Most upvoted comments

@Tyler-V @dhritzkiv

Actually, I wanted to emphasize that you can export just TypeOrmModule ([!] without method call).

So instead of this:

exports: [BService, TypeOrmModule.forFeature([EntityB])],

you can use this:

exports: [BService, TypeOrmModule],

yeah, I’ve tended to use the @Injectable({ providedIn: 'root' }) in angular recently so kinda forgot that.

I was just surprised that next < 6.3.1 starts fine (and works fine), but 6.3.1 crapped out on startup

Yes, but my point is that before 6.3.0 I didn’t have to export the service. Do I now have to go through all my modules and export the services? Surely a minor upgrade shouldn’t require source to be changed?

On Mon, 10 Jun 2019, 14:58 Cyril DUPETIT, notifications@github.com wrote:

@jmls https://github.com/jmls

import { Module } from ‘@nestjs/common’; import { FooService } from ‘./foo.service’;

@Module({ imports: [], providers: [FooService], exports: [FooService], <--------------------- }) export class FooModule {}

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nestjs/nest/issues/2359?email_source=notifications&email_token=AAHC546OPAVBO3VAQABBP53PZZM2DA5CNFSM4HVCAB7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXJ6NVA#issuecomment-500426452, or mute the thread https://github.com/notifications/unsubscribe-auth/AAHC547OTTPDB7VDDGM5MILPZZM2DANCNFSM4HVCAB7A .

I had the same problem. My project is quiet big, had to adjust up to 40 files. But I always wondered, why I could inject some intestables without being part of the module scope. I could solve everything and i was eager to do so, but I faced 1 problem.

I have some shared (global) modules for sending mails, sms, and push notifications. And all of these 3 modules are actually very similar in their structure for Module and Service. The only difference is, the Push Notification Module imports an Entity to use it’s repository.

The problem I faced then: I needed to import this Entity in every module where I imported the Push Notification Module, a behavior I never faced so far. If I import a Module B inside of Module A, Module B imports everything by itself, without importing Module B imports manually in Module A.

pushnotificaiton.module.ts

import { Module, Global } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PushNotificationLog } from '@/entities';
import { PushNotificationService } from './push-notification.service';

@Global()
@Module({
  imports: [TypeOrmModule.forFeature([PushNotificationLog])],
  providers: [PushNotificationService],
  exports: [PushNotificationService],
})
export class PushNotificationModule {}

pushnotification.service.ts

@Injectable()
export class PushNotificationService {
  @Inject('ConfigService')
  private readonly config: ConfigService;

  private readonly notificationRepository: BaseRepository<PushNotificationLog>;

  constructor(
    @InjectRepository(PushNotificationLog) notificationRepository: BaseRepository<PushNotificationLog>,
  ) {
    this.notificationRepository = notificationRepository;
  }

  // 1 public send handler
}

I solved this by removing the constructor and using the repository by importing getRepository from typeorm. A solution I don’t like.

v6.3.0 works fine

For anyone wondering how to resolve this for TypeORM modules:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { FooEntity } from './foo.entity';
import { FooService } from './foo.service';

const FooEntities = TypeOrmModule.forFeature([FooEntity]);

@Module({
  imports: [FooEntities],
  providers: [FooService],
  exports: [FooService, FooEntities], //<-re-export the entities
})
export class FooModule {}

6.3.1 after the scene, all dependencies used by the service layer in providers must be introduced in imports.