•
module 이란, @Module() 데코레이터가 달린 클레스 이다.
•
@Module() 데코레이터는 Nest가 어플리케이션 구조를 구성하는데 사용하는 메타데이터를 제공하니다. (make use of to-v : v 하는데 활용하다)
•
각각의 어플리케이션은 최소한 root module 이라는 하나의 모듈을 가지고 있어야 합니다.
•
root module 은 네스트가 application graph 를 만드는데 사용하는 스타팅 포인트 입니다.
•
application graph 란, 네스트가 모듈과 프로바이더의 관계와 디펜던시를 해결하는데 사용하는 내장 데이터 스트럭쳐 이니다.
•
아주작은 어플리케이션의 경우 이론적으로 단지 루트모듈만 필요할 수 있습니다. (하지만 전형적인 케이스는 아닙니다)
•
우리는 당신의 컴포넌트를 효과적으로 구성하는 방법으로 모듈이 강력하게 추천된다는 것을 강조하고 싶습니다.
•
결과적으로 어플리케이션은 여러개의 모듈들로 구성됩니다. (각각 밀접하게 관련된 기능 set을 캡슐랑화 합니다.)
•
@Module() 데코레이터는 하나의 오브젝트(아래의 프로퍼티들을 포함하는)를 받습니다. :
providers : 프로바이더는 네스트 인젝터에 의해 인스턴스화 되고, 최소한 이 모듈을 건너 공유될 수 있습니다.
controllers : 인스턴스화 되야 하는 이 모듈 안에 정의된 컨트롤러들의 집합
imports : 이 모듈에서 요청된 프로바이더들을 익스포트하는 모듈의 임포트 리스트 (말 겁나 어렵게하네)
exports : 이 모듈에서 제공하고 이 모듈을 가져오는 다른 모듈에서 사용할 수 있어야하는 프로바이더들의 하위집합
•
모듈은 프로바이더들을 기본적으로 캡슐화 합니다.
•
현재 모듈의 직접적인 부분이 아니거나, 임포트된 모듈이 익스포트하는 하지 않는 프로바이더들은 인젝트 하는 것이 불가능하니다.
•
당신은 모듈로부터 익스포트된 프로바이더들을 모듈의 public interface 나 API 라고 생각할 수 있습니다.
Feature modules (기능 모듈)
•
CatsController 와 CatsService 는 같은 어플리케잇녀 도메인에 속해있습니다.
•
이것들은 가깝게 연관되어 있기에, 이것을 feature module 로 옮기는 것은 메잌 센스 하다.
•
feature module 은 간단하게 특정 기능에 연관된 코드를 구성하고, 코드가 확실한 바운드 안에 있는 것을 유지한다.
•
이것은 우리가 복잡성과, SOLID 원칙의 개발 (특히 어플리케이션 이나 팀의 규모가 커짐에 따라) 을 매니지 하도록 도와준다.
•
To demonstrate this, we'll create the CatsModule
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
Plain Text
복사
HINT : nest g module cats
•
위에서 우리는 CatsModule 을 cats.module.ts 안에 선언하고, 관련된 모든 것들을 이 모듈에 넣었다
•
마지막 남은 일은 이 CatsModule 을 루트모듈에 임포트 하는 것이다.
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
Plain Text
복사
Shared modules
•
네스트에서 모듈은 기본적으로 싱글톤이다.
•
그리고 이것은 여러 모듈들이 서로 같은 프로바이더의 인스턴스를 쉽게 공유 할 수 있게 한다.
•
모든 모듈은 기본적으로 shared module 입니다.
•
한번 만들어지면 모든 모듈에서 재사용 될수 있습니다.
•
우리가 CatsService 인스턴스를 몇몇 다른 모듈들에서 쉐어 하기를 원한다고 상상해봅시다. (말을 왜케 어렵게하냐 진짜)
•
그러기 위해선, 우리는 첫째로 CatsService 프로바이더를 export 할 필요가 있습니다. 어떻게? 모듈의 exports array 에 더하는 것으로. 아래를 보세요
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 {}
Plain Text
복사
•
이제 CatsModule 을 임포트한 모든 모듈이 CatsService 를 엑세스 할 수 있습니다.
•
또한 모든 모듈과 같은 인스턴스를 공유합니다. (네스트의 거의 모든게 싱글턴 이니까)
Module re-exporting
•
위에서 본대로 모듈은 그들의 내부 프로바이더들을 내보낼 수 있습니다.
•
여기에 더불어 모듈들은 자신이 가져온 모듈을 다시 내보낼 수 있습니다.
•
아래의 예에서 CommonModule 은 CoreModule 이 가져오기도 하고, 내보내기도 합니다
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}
Plain Text
복사
Dependency Injection
•
모듈 클레스는 프로바이더들을 주입 할 수 있습니다. (예를들어, configuration 목적으로)
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) {}
}
Plain Text
복사
•
그러나 모듈클레스 그 자체는 프로바이더로 인젝트 될 수 없습니다. (왜냐면 circular dependency 때문에)
Global Modules
•
만약 당신이 같은 모듈들의 집합을 모든 곳에 임포트 해야 한다면, it can get tedious (지루 할 수 있다)
•
네스트와 다르게, Angular providers 는 글로벌 스코프로 등록된다.
•
일단 정의되면, 모든 곳에서 사용 될 수 있다.
•
하지만 네스트는 이와 다르게, 모듈 스코프내에서 프로바이더들을 캡슐화 합니다.
•
당신은 캐슐화된 모듈을 임포트하지 않고는, 모듈의 프로바이더들을 사용 할 수 없습니다.
•
만약 당신이 set of providers 를 모든 곳에 제공하기를 원한다면, (예를들어 helpers, database connections, etc.), @Global() 데코레이터를 이용하여 모듈을 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 {}
Plain Text
복사
•
@Global() 데코레이터는 모듈을 글로벌스코프에 존재하게 만듭니다.
•
글로벌 모듈은 일반적으로 루트나 코어 모듈에서, 오직 한번만 등록 되어야 합니다.
•
위의 예제에서 CatsService 프로바이더 는 어디에나 있으며, 이 서비스를 주입하고자 하는 모듈들은 CatsModule 을 그들의 imports array 에 임포트 할 필요가 없습니다.
HINT 모든 것을 글로벌로 만드는 것은 좋은 디자인이 아닙니다. 글로벌 모듈은 필요한 보일러플레이트의 양을 줄이는데 사용 할 수 있습니다. 일반적으로 imports array 를 통해 가져오는 것이 선호됩니다.
Dynamic modules
•
네스트의 모듈 시스템은 dynamic modules 라고 불리는 강력한 기능을 포함합니다.
•
이 기능ㅇ르 사용하면 프로바이더들을 동적으로 등록하고, 구성 할 수 있는 사용자 지정 가능한 모듈을 쉽게 만들 수 있습니다.
•
여기 서 다이나믹모듈 을 광범위하게 다룹니다.
•
이 쳅터에서는, 간단하게 브리핑 하겠습니다.
•
아래 예는 DatabaseModule 이라는 다이나믹 모듈의 정의 입니다. :
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
Plain Text
복사
HINT : forRoot() 메소드는 동기화되거나, 비동기화 되는 다이나믹모듈을 리턴 할 수있습니다.
•
이 모듈은 @Module() 데코레이터 메타데이터 에서, Connection 프로바이더를 기본적으로 정의했다.
•
그러나 추가적으로 (forRoot() 메소드를 통해 전달된 entities 와 options objects 에 따라) 프로바이더의 컬렉션을 노출한다 (이 프로바이더의 컬렉션을 예를들어 repositories 라 하자)
•
동적모듈에 의해 반환된 프로퍼티들은 ovrride 되는 것이 아니라, @Module() 데코레이터에 정의된 기본 module 메타데이터에서 extend 된다.
•
이 방법으로 정적으로 선언된 *Connection 프로바이더와 동적으로 생성된 repository 프로바이더가 모듈에서 exported 된다.
•
만약 동적 모듈을 글로벌하게 등록하고 싶으면, 반환값에 global 프로퍼티를 true 로 설정하면 된다.
{
global: true,
module: DatabaseModule,
providers: providers,
exports: providers,
}
Plain Text
복사
•
DatabaseModule 은 아래와 같은 방법으로 임포트되고, 구성될 수 있다.
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 {}
Plain Text
복사
•
만약 다이나믹 모듈을 re-export 하고싶다면, forRoot() 메소드콜을 생략하고 exports array 에 넣으면된다.
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 {}
Plain Text
복사