Modules

이연중·2021년 7월 26일
0

NestJS

목록 보기
4/22

@Module() 데코레이터로 주석이 달린 클래스이다.

해당 데코레이터는 Nest가 어플리케이션의 구조를 구성하는데 사용하는 메타데이터를 제공한다.

각 어플리케이션은 루트 모듈이라는 하나 이상의 모듈이 있다.

루트 모듈은 Nest가 어플리케이션 그래프(Nest가 module과 provider의 관계와 의존성을 해결하기 위해 사용하는 내부 데이터 구조)를 빌드하는데 사용하는 시작점이다.

대부분의 어플리케이션에서 결과 아키텍처는 각각 밀접하게 관련된 기능 집합을 캡슐화하는 여러 모듈을 사용한다.

providersNest 인젝터에 의해 인스턴스화 되고 적어도 이 모듈에서 공유될 수 있는 프로바이더
controllers인스턴스화 되어야 하는 이 모듈에 정의된 컨트롤러 세트
imports이 모듈에 필요한 프로바이더를 내보내는 가져온 모듈 목록
exports이 모듈에서 제공하고 이 모듈을 임포트하는 다른 모듈에서 사용할 수 있어야 하는 프로바이더의 하위집합

모듈은 기본적으로 프로바이더를 캡슐화한다.

Feature Modules


CatsControllerCatsService는 동일한 어플리케이션 도메인에 속하고, 밀접하게 관련되어 있으므로 별도의 기능 모듈(Feature Module) 만든다.(CatsModule)

Feature Module은 특정 기능과 관련된 코드를 구성해 코드를 체계적으로 유지하고 명확한 경계를 설정한다.

이는 어플리케이션 및 팀의 규모가 커짐에 따라 복잡성을 관리하고 SOLID 원칙에 따라 개발하는데 도움이 된다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}

nest -g module cats을 이용해 모듈을 생성하면 된다.

위 과정을 통해 CatsModule을 정의하고 해당 모듈과 관련된 모든 것들을 cats 디렉토리에 옮겼다.

이후에는 이 모듈을 루트 모듈에 포함시켜줘야 한다.

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule {}

여기까지 했을때, 디렉토리의 구조는 다음과 같다.

Shared Modules


Nest에서 모듈은 기본적으로 싱글톤이므로, 여러 모듈 간 쉽게 Provider의 동일 인스턴스를 공유할 수 있다.

모든 모듈은 자동으로 Shared Module이다. 일단 생성되면, 모든 모듈에서 재사용할 수 있다.

여러 모듈 간 CatsService의 인스턴스를 공유한다고 해보자.

이렇게 하려면 먼저 아래와 같이 모듈의 exports 배열에 CatsService Provider를 추가하여 export해야 한다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
  exports: [CatsService]
})
export class CatsModule {}

이제 CatsModule을 import하는 모든 모듈은 CatsService에 접근할 수 있으며, 동일한 인스턴스를 공유한다.

Module Re-exportion


위처럼 모듈은 내부 Provider를 내보낼 수 있다. 또한 가져온 모듈을 다시 내보낼 수 있다.

@Module({
  imports: [CommonModule],
  exports: [CommonModule],
})
export class CoreModule {}

위 모듈을 import하는 모듈은 자동으로 두 개의 모듈을 import한 셈인 것이다.

Dependency Injection


모듈 클래스에 Provider도 주입할 수 있다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {
  constructor(private catsService: CatsService) {}
}

하지만, Module 클래스는 순환 의존성에 의해 Provider에 주입될 수 없다.

위같은 경우 CatsModuleCatsService를 의존성 주입할 수는 있지만, CatServiceCatsModule을 의존성 주입할 수는 없다.

Global Modules


Nest는 모듈 범위 내에서 Provider를 캡슐화 한다. 그렇기에 사용하려는 모듈이 export되지 않았거나, 해당 모듈을 import하지 않고서는 사용(의존성 주입)할 수 없다

하지만, 즉시 사용될 수 있어야 하는 Provider 같은 경우(ex: Helper, Database Connection etc...) @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 {}

해당 데코레이터는 모듈을 전역 범위로 만든다.

전역 모듈은 일반적으로 Root 또는 Core 모듈에서 한번만 등록해야 한다.

위 예에서 CatsService Provider는 어디에서는 사용할 수 있을 것이며, 해당 서비스를 의존성 주입하기 위해 import를 할 필요가 없다.

반드시 전역으로 등록해야하는 모듈이 아닌 경우에는 웬만하면, 전역 범위로 모듈을 설정하는 것을 권장하지 않는다.(최대한 export, import로)

참고

https://docs.nestjs.kr/modules

profile
Always's Archives

0개의 댓글