참고 문서
Module이란?

- @Module() 데코레이터로 정의된 클래스이며, NestJS에서 어플리케이션을 구조화하고 관리하는 기본 단위이다.
- 모든 NestJS 앱은 최소한 하나의 루트 모듈(AppModule) 을 가진다.
- 모듈은 providers, controllers, imports, exports로 구성되어 내부 구성요소를 캡슐화하며 재사용 가능하게 만든다.
주요 속성
- providers: 서비스, 유틸 등 의존성 주입 대상
- controllers: 요청/응답 처리용 컨트롤러
- imports: 다른 모듈을 현재 모듈에서 사용
- exports: 외부 모듈에서 사용할 수 있도록 내보냄
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
imports:[AnyModule],
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService]
})
export class CatsModule {}
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
exports를 해야하는 이유
- exports를 사용하지 않으면 해당 모듈의 Provider를 다른 모듈에서 사용할 수 없다.
- 즉, provider는 모듈 내부에서 기본적으로 캡슐화되어 있어서 exports 하지 않으면 외부에 공개되지 않는다.(private 설정이 Default라고 생각하는 게 편할 것 같다.)
- 위 코드를 예시로 들면, CatsService를 담고 있는 Module에서 exports: [CatsService]를 설정해주지 않는다면, 다른 모듈에서 CatsService에 접근할 수 없다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
imports:[AnyModule],
controllers: [CatsController],
providers: [CatsService],
exports: []
})
export class CatsModule {}
@Module({
imports: [CatsModule],
providers: [AnyService],
})
export class AnyModule {}
@Injectable()
export class AnyService {
constructor(private catsService: CatsService) {}
}
- AnyModule에서는 CatsModule에 있는 CatsService에 접근할 수 없다.
- 위와 같은 경우 CatsService를 주입하려 하면 NestJS는 Cannot resolve dependency 에러를 던지게 된다.
Global 모듈 만들기
- 다른 모듈에 접근할 때 해당 모듈에서 imports:[Module...]로 불러와야한다.
- 하지만 @Global() 데코레이터를 사용하면 다른 모듈에서 해당 모듈에 접근할 때 imports를 하지 않아도 바로 사용이 가능하다.
- 단, exports로 사용할 Provider를 설정해야 한다!!
- 보통 공통 서비스(Helper, Logger, DB, Auth) 등은 Global로 설정한다.
import { Module, Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Global()
@Module({
controllers: [CatsController],
providers: [CatsService],
exports: [CatsService],
})
export class CatsModule {}
@Injectable()
export class OtherService {
constructor(private catsService: CatsService) {}
}
Dynamic Module이란?
- 반적으로 모듈은 정적으로 정의되며, @Module() 데코레이터 내부에서 providers, controllers, imports, exports 등을 미리 지정해야 한다.
- 하지만 경우에 따라 앱이 실행될 때 동적으로 모듈을 설정해야 하는 상황이 발생할 수 있다.
- 예를 들어 데이터베이스 연결 → 환경 변수에 따라 다른 DB에 연결해야 할 때, API 인증 모듈 → 특정 설정 값에 따라 다른 인증 전략을 사용할 때, 다국어 지원 (i18n) → 설정에 따라 지원하는 언어를 다르게 구성할 때
- 이러한 경우 동적 모듈(Dynamic Module) 을 사용하면 모듈을 유연하게 생성 및 구성할 수 있다.
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
exports: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
forRoot() 메서드를 통해 모듈을 생성할 때 옵션을 받을 수 있음.
- 이 옵션을 기반으로
createDatabaseProviders() 함수를 호출하여 동적으로 Provider를 생성.
providers와 exports를 설정하여 해당 설정을 다른 모듈에서도 사용 가능하게 함.
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
@Module({
imports: [DatabaseModule.forRoot(['User', 'Product'], { sync: true })],
})
export class AppModule {}
- forRoot() 메서드에서 ['User', 'Product'] 엔티티와 sync: true 옵션을 받아 런타임에서 동적으로 provider를 설정한다.
글로벌 동적 모듈
- 만약 전역(Global)으로 사용할 동적 모듈을 만들고 싶다면 { global: true } 옵션을 추가할 수 있다.
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
global: true,
module: DatabaseModule,
providers: providers,
exports: providers,
};
}