NestJS/NestJS Slack 클론

NestJS Slack - 2. 시작 및 세팅

PHM 2022. 7. 12. 14:30

핫 리로딩 ( hot-reload )

공식문서 : https://docs.nestjs.com/recipes/hot-reload

npm i --save-dev webpack-node-externals run-script-webpack-plugin webpack

- webpack-hmr.config.js

const nodeExternals = require('webpack-node-externals');
const { RunScriptWebpackPlugin } = require('run-script-webpack-plugin');

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['webpack/hot/poll?100', options.entry],
    externals: [
      nodeExternals({
        allowlist: ['webpack/hot/poll?100'],
      }),
    ],
    plugins: [
      ...options.plugins,
      new webpack.HotModuleReplacementPlugin(),
      new webpack.WatchIgnorePlugin({
        paths: [/\.js$/, /\.d\.ts$/],
      }),
      new RunScriptWebpackPlugin({ name: options.output.filename }),
    ],
  };
};

- main.ts

declare const module: any;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const port = process.env.PORT || 3000;
  await app.listen(port);
  console.log(`listening on port ${port}`);

  if (module.hot) {
    module.hot.accept();
    module.hot.dispose(() => app.close());
  }
}
bootstrap();

-package.json

"start:dev": "nest build --webpack --webpackPath webpack-hmr.config.js --watch"

데코레이터 ( 애노테이션 ) - IoC(제어의 역전) Inversion of Control

* 다만 module을 직접 구성해야한다는 점에서 스프링보다 IoC가 약하다

 

Service의 역할 : 비지니스 로직의 분리

    ㆍ비즈니스로직 : 실제 동작

    ㆍ서비스는 요청, 응답에 대해서는 모른다.

    ㆍ컨트롤러는 요청, 응답을 알아야 한다.

    ㆍ중복제거, 독립적이다.

 

* res 쓰면 안 좋은점 : 테스트할 때 mock 데이터를 만들어서 테스트해야함

 

- 모듈 import 시 .forRoot() / .forFeature() / .register()가 붙는 것은 ({  }) 설정을 넣어 주기 위해서 붙는 것


.env 파일 사용

1. module

- provider에 ConfigService 적용

@Module({
  imports: [ConfigModule.forRoot({ isGlobal: true })],
  controllers: [AppController],
  providers: [AppService, ConfigService],
})
export class AppModule {}

2. Service

- 생성자 적용 후  .get('NAME')

@Injectable()
export class AppService {
  constructor(private readonly configService: ConfigService) {}

  getHello(): string {
    return this.configService.get('NAME');
    		// process.env.DB_PASSWORD
  }
}

- process.env 는 외부 객체이므로 nest와 상관이 없음 그러므로 configService를 사용하는 것이 더 좋음


const getEnv = async () => {
  const response = await axios.get('/비밀키요청');
  return response.data; 
};

@Module({
  imports: [ConfigModule.forRoot({ isGlobal: true, load: [getEnv] })],
})

- load이용시 외부서버에서의 비밀키를 env로 사용가능!


미들웨어

- middle.middleware.ts

@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  private logger = new Logger('HTTP');

  use(request: Request, response: Response, next: NextFunction): void {
    const { ip, method, originalUrl } = request;
    const userAgent = request.get('user-agent') || '';

    response.on('finish', () => {
      const { statusCode } = response;
      const contentLength = response.get('content-length');
      this.logger.log(
        `${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip}`,
      );
    });

    next();
  }
}

    ㆍLogger('HTTP')의 HTTP는 debug할 때 편함

    ㆍ미들웨어를 사용할 때는 next()를 써야 다음으로 넘어간다.

    ㆍ코드 순서가 라우터가 끝나고 난 다음 ( next() 이후 ) response.on이 제일 마지막이다.

        비동기이기에 ( 노드 특징 : 실행 순서가 달라질 수 있다 )

-  app.module.ts

    ㆍ미들웨어 적용시

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer): any {
    consumer.apply(LoggerMiddleware).forRoutes('*');
  }
}

 

* 실무에서는 nest morgan 패키지 사용..


- implements : 에디터와 ts의 강점을 적용, 컴파일에 좋음

- @Injectable()

    ㆍDI ( Dependency Injection ) : provider에 연결되어있는 것들을 보고 의존성 주입을 해준다.

    ㆍprovider에 해당 파일을 넣어줘야함.

 

Providers

providers: [AppService]

// 원형
providers: [
    {
      provide: AppService,	// "고유한 키"
      useClass: AppService,	// 해당클래스를 쓰겠다
      // useValue : 해당 값을 쓰겠다
      // useFactory: () => { return }
    },
    {
      provide: 'CUSTOM_KEY',
      useValue: 'CUSTOM_VALUE',
    },
]

- 스프링에서는 의존성주입을 자동으로 해주지만 nest에서는 이 모듈에서 내가 원하는 값을 주입해준다.

- 사용 시

constructor(
    private readonly appService: AppService,		// @Injectable() 클래스
    @Inject('CUSTOM_KEY') private readonly customValue	// 커스텀
){}