처음부터 차근차근

[NestJS] Module 본문

FrameWork/NestJS

[NestJS] Module

HangJu_95 2023. 11. 24. 23:42
728x90

Module이란?

Module은 Nest가 Application structure를 Organize하는데 사용되는 Metadata를 제공한다.

Nest에는 기본적으로 Root Module이라는 것이 존재한다.

루트 모듈은 Nest가 애플리케이션 그래프(Nest가 module 과 Provider의 relationship & dependencies를 해결하는데 사용되는 내부 date 구조)를 구축하는데 사용하는 시작점이다.

또한 Nest에서는 모듈 간 연결이 효율적으로 가능하다.

root module 외에도 추가로 밀접하게 연관된 기능들을 모아 여러개의 모듈을 구성하는 것을 권장하며, Nest에서는 이를 효율적으로 가능하도록 도와준다.

 

@Module 데코레이터는 Nest가 App 구조를 만들 때 사용할 수 있는 메타데이터를 제공하는 역할을 하며, 아래의 속성들을 갖고 이쓴ㄴ 객체를 파라미터로 받는다.

  • providers: 인스턴스화 되어 해당 모듈에서 공유될 수 있는 Provider들
  • controllers: 인스턴스화 되어 해당 모듈에서 공유될 수 있는 Controller들
  • imports: import할 외부 모듈 (해당 모듈이 export한의 Provider를 사용하기 위함)
  • exports: 자신의 provider들 중 자신을 import할 시 사용을 허용할 Provider들 (Provider 자체와 token 모두 사용 가능)

모듈은 기본적으로 자신의 Provider들을 캡슐화하여 외부에 공개하지 않으며, 즉 노출되지 않은 프로바이더는 다른 모듈에 주입이 불가능하다.

Feature Modules

특정 기능을 기준으로 연관된 컴포넌트들을 묶은 단위를 기능 모듈이라고 한다.

이는 특정 기능과 관련된 코드를 구성하여 코드를 체계적으로 유지하고 명확한 경계를 설정해주며, 이를 통해 app이나 팀의 규모가 커짐에 따라 커지는 복잡성을 관리하는데 도움을 주고 SOLID 원칙으로 개발하는 데 도움이 된다.

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

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

위 예시는 CatsModule을 만든 예시이다. 이는 Root Module에 추가해줘야 Nest에서 이를 인지하고 Application Structure를 구성할 수 있다.

Shared modules

Nest에서 모듈은 기본적으로 싱글톤이다.(Node의 특성)

이런 특성으로 인해 Nest에서는 여러 모듈간에 쉽게 공급자의 동일한 인스턴스를 공유할 수 있다.

모든 모듈은 자동으로 공유 모듈이다. 따라서 다른 어떤 모듈에서도 import가 가능하다.

CatsService의 인스턴스를 공유하는 상황을 가정해본다면

//cats.module.ts

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 {}

export 배열에 CatsService 프로바이더를 추가하여 프로바이더를 노출시켜야 한다.

이를 통해 CatsModule을 가져오는 모듈에서는 CatsService에 접근할 수 있으며, 이 모듈을 가져오는 다른 모듈과 동일한 인스턴스를 공유한다.

Module re-exporting

모듈은 모듈 내부의 프로바이더를 노출시킬 수 있으며, 또한 가져온 모듈을 다시 내보낼 수 있다.

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

의존성 주입

모듈 클래스도 프로바이더를 주입할 수 있다.(설정 관련된 목적을 위해)

그러나 모듈 클래스 자체는 순환 종속성으로 인해 자체적으로 공급자로 주입될 수 없다.(이는 순환 종속성 시간에 다시 본다)

Global modules

동일한 모듈을 매번 import하는 수고를 덜기 위해 모듈을 전역 스코프로 설정할 수 있다.

모듈에 @Global() 데코레이터를 붙이면 import 없이 해당 모듈의 Provider를 사용할 수 있게 된다.

여기서 중요한 점은 Global module은 일반적으로 루트 또는 코어 모듈에 의해 단 한번만 등록되어야 한다.

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 {}

Dynamic Module

동적 모듈은 프로바이더를 동적으로 등록하고 구성할 수 있는 커스터마이징 모듈을 쉽게 만들 수 있다.

데이터베이스 기능을 다루는 동적 모듈을 예시로 보자.

import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';

@Module({
  providers: [Connection],
})
// 데이터베이스 모듈을 동적으로 생성
export class DatabaseModule {
  // forRoot 메서드에 전달된 entities, options 객체에 따라 Repository와 같은 여러 프로바이더를 노출시킨다.
  static forRoot(entities = [], options?): DynamicModule {
    const providers = createDatabaseProviders(options, entities);
    return {
      module: DatabaseModule,
      providers: providers,
      exports: providers,
    };
  }
}

동적 모듈이 반환하는 속성은 @Module() 데코레이터에 정의된 모듈의 기본적인 메타데이터를 재정의(override)하지 않고 확장합니다. 이렇게하면 정적으로 선언된 연결 제공자와 동적으로 생성된 저장소 제공자가 모두 모듈에서 내보내집니다.

전역 범위에 동적 모듈을 등록하려면 global 속성을 true로 설정합니다.

{
  global: true,
  module: DatabaseModule,
  providers: providers,
  exports: providers,
}

데이터베이스 모듈은 아래와 같은 방식을 통해 가져오고 설정할 수 있다.

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [DatabaseModule.forRoot([User])],
  exports: [DatabaseModule],
})
export class AppModule {}

또한 export를 통해 동적 모듈을 내보낼 수 있다.

이 부분은 추후 동적 모듈을 통해 자세하게 다룬다.

참조

https://docs.nestjs.com/modules

https://www.wisewiredbooks.com/nestjs/overview/05-modules.html

https://gongmeda.tistory.com/50

'FrameWork > NestJS' 카테고리의 다른 글

[NestJS] Middleware  (0) 2023.11.25
[NestJS] Request Lifecycle  (0) 2023.11.25
[NestJS] Providers  (0) 2023.11.24
[NestJS] Controller  (1) 2023.11.24
[NestJS] NestJS는 왜 만들어졌을까??  (1) 2023.11.13