상똥이의 Back-End 공부방

[Nest.js] Modules 본문

Nest.JS/Docs

[Nest.js] Modules

상똥백 2024. 9. 4. 18:29

 

Module은 @Module() 데코레이터를 사용하는 클래스입니다. @Module() 데코레이터는 Nest가 애플리케이션 구조를 조직할 수 있도록 메타데이터를 제공합니다.

 

각각의 애플리케이션은 적어도 하나의 모듈(루트 모듈)을 가지고 있습니다. 루트 모듈은 애플리케이션 그래프(Nest가 모듈과 프로바이더 사이의 관계와 의존성을 해결하는데 사용하는 내부 데이터 구조)를 만드는 시작점입니다. 아주 작은 애플리케이션이 이론적으로 루트 모듈만을 가지기 때문에 이런 경우는 일반적이지 않습니다. 모듈이 컴포넌트를 구성하는데에 효과적인 방법이라고 강력히 추천하고 싶습니다. 따라서 대부분의 애플리케이션에서 결과적으로 여러 모듈을 사용하여, 각각 밀접하게 관련된 기능 집합을 캡슐화하는 아키텍처를 채택하게 됩니다.

 

@Module() 데코레이터는 속성을 설명하는 단일 객체를 가집니다.:

providers
프로바이더는 Nest의 주입으로 인해 인스턴스화되며 이 모듈을 거쳐 공유됩니다.
controllers
이 모듈에 정의된 인스턴스화 되어야 하는 컨트롤러 집합
imports
이 모듈에 필요한 프로바이더를 내보내는 모듈 모음
exports
이 모듈을 통해 제공되고 이 모듈을 import하는 다른 모듈에서 사용될 수 있어야 하는 프로바이더의 부분집합. 프로바이더 그 자체를 사용할 수도 있고 그저 토큰만을 사용할 수도 있음

 

모듈은 기본적으로 프로바이더를 캡슐화합니다. 이는 현재 모듈의 일부가 아니거나 임포트된 모듈에서 내보내지 않은 제공자를 주입할 수 없다는 것을 의미합니다. 따라서 모듈에서 내보낸 제공자를 모듈의 공개 인터페이스 또는 API로 간주할 수 있습니다.

 


Feature modules

CatsController와 CatsService는 같은 애플리케이션 도메인에 속합니다. 이 둘은 밀접하게 연결되어 있으므로 기능 모듈로 이동시키는 것이 합리적입니다. 기능 모듈은 특정한 기능과 관련있는 코드를 조직해 코드를 정리된 상태로 유지하고 경계를 깔끔하게 합니다. 이렇게 하면 복잡성을 관리하고 SOLID 원칙에 따라 개발할 수 있으며, 특히 애플리케이션이나 팀의 규모가 커질수록 더욱 중요해집니다. 이를 입증하기 위해 CatsModule을 생성해보겠습니다.

// cats/cats.module.ts

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

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}
HINT
모듈을 CLI 명령어로 생성하고 싶다면, $ nest g module cats 명령어를 입력하세요.

 

위에서 cats.module.ts 파일 안에 CatsModule을 정의했으며 이 모듈과 관련된 모든 것들을 cats 경로 안에 옮겼습니다. 다음으로 해야할 마지막 일은 루트 모듈(app.module.ts 파일 안에 정의된 AppModule)에서 이 모듈을 import하는 것입니다. 

// app.module.ts

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

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

 

이제 파일 구조는 아래와 같을 것입니다.

 


Shared modules

Nest에서는 모듈이 기본적으로 싱글톤이므로, 여러 모듈 간에 동일한 프로바이더 인스턴스를 손쉽게 공유할 수 있습니다.

모든 모듈은 자동으로 공유된 모듈입니다. 한 번 생성되면 어느 모듈에서든 재사용될 수 있습니다. 다른 모듈이 CatsService를 공유받기 위해서 CatsService 프로바이더를 모듈의 exports 배열에 추가함으로써 export해야합니다.

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

 

이제 어느 모듈이든 CatsModule을 import하기만 하면 CatsService에 접근할 수 있으며 같은 인스턴스를 공유할 수 있습니다.

 


Module re-exporting

위에서 보았듯이 모듈은 자신들의 내부에 있는 프로바이더를 export할 수 있습니다. 또한 자신들이 import한 것을 다시 export할 수도 있습니다. 아래의 예시에서 CommonModule은 CoreModule에서 import도기도 하며 export되기도 하므로, 다른 모듈들이 사용할 수 있도록 합니다.

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

 


Dependency injection

모듈 클래스는 프로바이더를 주입할 수 있습니다. (설정 등의 목적으로)

// cats.module.ts

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

 

그러나 모듈 클래스 자체는 순환 의존성 때문에 프로바이더로 주입될 수 없습니다.

 


Global modules

만약 특정 모듈을 어느곳에서나 import해야하는 경우 시간이 걸릴 수 있습니다. Nest와 달리 Angular 프로바이더는 전역적으로 설치되어있습니다. 한 번 정의되면 어느곳에서나 사용할 수 있는 것입니다. 하지만 Nest에서는 모듈 범위 안에 프로바이더를 캡슐화합니다. 캡슐화하는 모듈을 import하지 않고서는 모듈의 프로바이더를 사용할 수 없습니다.

 

어디에서든 사용될 수 있어야 하는 프로바이더(데이터베이스 등)를 제공하고 싶다면 모듈을 @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 {}

 

@Global() 데코레이터는 모듈을 전역 범위로 만들어줍니다. 전역 모듈은 한 번만 설치하면 되고, 일반적으로 루트나 핵심 모듈입니다. 위의 예시에서 CatsService 프로바이더는 어디에서나 사용될 수 있으며 그 서비스를 주입하고자 하는 모듈은 CatsModule을 굳이 import하지 않아도 됩니다.

HINT
모든 것을 전역범위로 만들어주는 것은 좋은 생각이 아닙니다. 전역 모듈은 코드의 중복을 줄이기 위한 것입니다.

 


Dynamic modules

Nest 모듈 시스템은 동적 모듈이라는 강력한 기능을 포함합니다. 이 기능은 설치하고 프로바이더를 다양하게 구성할 수 있는 커스텀 가능한 모듈을 쉽게 생성할 수 있도록 해줍니다. 동적 모듈에 대해서는 여기에서 자세히 다룹니다. 이 장에서는 모듈에 대한 소개를 마칠 수 있도록 짧은 개요를 제공합니다.

 

아래 예시는 DatabaseModule로, 동적 모듈의 예시입니다.:

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,
    };
  }
}
HINT
forRoot() 메서드는 동기/비동기의 동적 모듈을 반환합니다.

 

이 모듈은 기본적으로 @Module() 데코레이터 메타데이터에 의해 Connection 프로바이더를 정의하지만, 추가로 forRoot() 메서드에 전달된 엔티티 및 옵션 객체에 따라 여러 제공자를 노출합니다. 예를 들어, 리포지토리 제공자들이 포함될 수 있습니다. 동적 모듈이 반환하는 속성은 @Module() 데코레이터에서 정의된 기본 모듈 메타데이터를 덮어쓰지 않고 확장합니다. 따라서 정적으로 선언된 Connection 프로바이더와 동적으로 생성된 리포지토리 제공자 모두 모듈에서 내보낼 수 있습니다.

 

만약 동적 모듈을 전역 범위로 설치하고 싶다면, global 속성을 true로 설정하면 됩니다.

{
  global: true,
  module: DatabaseModule,
  providers: providers,
  exports: providers,
}
WARNING
앞서 언급했듯이, 모든 것을 전역 범위로 설정하는 것은 좋은 선택이 아닙니다.

 

DatabaseModule은 다음과 같이 import될 수 있습니다.

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

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

 

만약 동적 모듈을 re-export하고 싶다면, forRoot() 메서드를 생략하면 됩니다.

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

 

Dynamic modules 챕터에서 더 자세히 확인할 수 있으며, 작동 예시를 포함하고 있습니다.

HINT
이 장에서는 `ConfigurableModuleBuilder`를 사용하여 매우 맞춤화 가능한 동적 모듈을 구축하는 방법을 배울 수 있습니다.

 

원문: https://docs.nestjs.com/modules

'Nest.JS > Docs' 카테고리의 다른 글

[Nest.js] Exception filters  (1) 2024.09.08
[Nest.js] Middleware  (0) 2024.09.05
[Nest.js] Providers  (0) 2024.09.04
[Nest.js] Controllers  (0) 2024.09.04
[Nest.js] First steps  (0) 2024.03.19