NestJS Slack - 2. 시작 및 세팅
핫 리로딩 ( 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 // 커스텀
){}