{
"name": "typescript-express-basic",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "tsc",
"build:watch": "tsc -w",
"dev": "NODE_ENV=dev ts-node-dev --respawn --transpile-only src/start.ts",
"start:dev": "nodemon --watch src --delay 500ms --exec ts-node src/start.ts",
"start": "NODE_ENV=production node build/start.js"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/express": "^4.17.13",
"@types/morgan": "^1.9.3",
"@types/multer": "^1.4.7",
"@types/node": "^16.4.12",
"nodemon": "^2.0.12",
"ts-node": "^10.1.0",
"ts-node-dev": "^1.1.8",
"typescript": "^4.3.5"
},
"dependencies": {
"dotenv": "^10.0.0",
"express": "^4.17.1",
"morgan": "^1.10.0",
"multer": "^1.4.2",
"winston": "^3.3.3",
"winston-daily-rotate-file": "^4.5.5"
}
}
$ npm i -D @types/express
$ npm i express
$ npm i -D @types/node
$ npm i -D ts-node
$ npm i -D ts-node-dev
$ npm i -D nodemon
$ npm i -D @types/morgan
$ npm i morgan
$ npm i winston winston-daily-rotate-file
$ npm i -D @types/multer
$ npm i multer
$ npm i dotenv
$ npm i path
"scripts": {
"build": "tsc",
"build:watch": "tsc -w",
"dev": "NODE_ENV=dev nodemon --watch src/ --delay 500ms --exec ts-node src/start.ts",
"start:dev": "NODE_ENV=dev ts-node-dev --respawn --transpile-only src/start.ts",
"start": "NODE_ENV=production node build/start.js"
},
dev
$ npm run dev
nodemon - 코드를 변경할 때마다 node를 재실행 시켜주는 모듈
--watch {folder} : 설정한 폴더안에 변화가 있으면 감지해서 재시작함
--exec ts-node : ts파일을 nodemon으로 실행시킬 수 있게함
start:dev
$ npm run start:dev
ts-node-dev - ts파일로 node dev서버 실행
start
$ npm run start
ts를 빌드한 js file로 node 서버 시작
ts-express-basic
├── node_modules
├── env
│ └── server.env
├── logs
├── src
│ ├── config
│ │ ├── env.ts
│ │ ├── route.ts
│ │ ├── logger.ts
│ │ └── morgan.ts
│ ├── controller
│ │ └── test.ts
│ ├── app.ts
│ └── start.ts
├── package.json
└── tsconfig.json
DB_HOST=
DB_USER=
DB_DATABASE=
DB_PASSWORD=
DB_PORT=
import path from "path";
import dotenv from "dotenv";
const config = dotenv.config({
path : path.join(__dirname, '../../env/server.env')
})
export const env = {
database : {
host: process.env.DB_HOST,
user: process.env.DB_USER,
database: process.env.DB_DATABASE,
password: process.env.DB_PASSWORD,
port: Number(process.env.DB_PORT)
}
}
import express from 'express';
const router = express.Router();
export default router
import winston from 'winston';
import winstonDaily from 'winston-daily-rotate-file';
const logDir = 'logs'; // logs 디렉토리 하위에 로그 파일 저장
const { combine, timestamp, printf, colorize} = winston.format;
// Define log format
const logFormat = printf(info => { return `[ ${info.level} ] ${info.timestamp} : ${info.message}`});
/*
* Log Level
* error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
*/
const logger = winston.createLogger({
format:
combine(
timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
logFormat,
),
transports: [
// info 레벨 로그를 저장할 파일 설정
new winstonDaily({
level: 'info',
datePattern: 'YYYY-MM-DD',
dirname: logDir,
filename: `%DATE%.log`,
maxFiles: 30, // 30일치 로그 파일 저장
zippedArchive: true,
}),
// error 레벨 로그를 저장할 파일 설정
new winstonDaily({
level: 'error',
datePattern: 'YYYY-MM-DD',
dirname: logDir + '/error', // error.log 파일은 /logs/error 하위에 저장
filename: `%DATE%.error.log`,
maxFiles: 30,
zippedArchive: true,
}),
],
});
// Production 환경이 아닌 경우(dev 등)
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: combine(
colorize({ all: true }), // 색깔 넣어서 출력
logFormat,
)
}));
}
export default logger;
import morgan, { StreamOptions } from "morgan";
import logger from "./logger";
const combined = ':remote-addr - :remote-user ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
// :method / request에 대한 HTTP method | :url 요청된 URL | :status HTTP 상태 | :response-time 응답시간 | :remote-addr 사용자의 IP 주소 | :http-version HTTP version |
const morganFormat = process.env.NODE_ENV !== "production" ? 'dev' : combined; // NOTE: morgan 출력 형태
const stream: StreamOptions = { // morgan log 출력 설정 winston logger 사용
write: (message) => logger.info(message),
};
const morganMiddleware = morgan( morganFormat,{ stream }); // morgan use setting
export default morganMiddleware;
import morgan, { StreamOptions } from "morgan";
import logger from "./logger";
const combined = ':remote-addr - :remote-user ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"'
// :method / request에 대한 HTTP method | :url 요청된 URL | :status HTTP 상태 | :response-time 응답시간 | :remote-addr 사용자의 IP 주소 | :http-version HTTP version |
const morganFormat = process.env.NODE_ENV !== "production" ? 'dev' : combined; // NOTE: morgan 출력 형태
const stream: StreamOptions = { // morgan log 출력 설정 winston logger 사용
write: (message) => logger.info(message),
};
const morganMiddleware = morgan( morganFormat,{ stream }); // morgan use setting
export default morganMiddleware;
import express, { Request, Response } from 'express';
import router from '../config/route';
import logger from '../config/logger';
const testRoute = router;
testRoute.get('/test', (req: Request, res: Response) => {
res.status(200).send();
});
export default testRoute
import express, {Request, Response} from "express";
import logger from './config/logger';
import morganMiddleware from "./config/morgan";
import router from './config/route';
import testRoute from './controller/testRoute';
export class App{
public app;
constructor(){
this.app = express();
this.setMiddleware();
this.setExpress();
}
private setExpress() : void { // express setting
try {
this.setRoute();
} catch(err){
logger.error(err);
}
}
private setRoute() : void { // express routing controller setting
this.app.use(router);
this.app.use(testRoute);
}
private setMiddleware() : void {
this.app.use(express.json()); // request body parsing setting
this.app.use(express.urlencoded({ extended: false })); // request body parsing setting
this.app.use(morganMiddleware) // morgan http logging setting
}
}
import { App } from './app';
import logger from './config/logger';
try {
const app = new App().app;
const port : number = 3000;
app.listen(port, () => {
logger.info(` NODE ENV = ${process.env.NODE_ENV} `)
logger.info(`Server is running on port : ${port}`);
});
} catch(err) {
logger.error(err);
}