Envrioment Variables, 환경변수는 프로세스가 컴퓨터에서 동작하는 방식에 영향을 미치는 동적인 값들의 모임이라고 정의되어있습니다. 즉 운영체제 상에서 동작하는 응용소프트웨어가 참조하기 위한 설정들이 기록되는 곳입니다.
웹 애플리케이션에도 어플리케이션이 동작하기 위해 필요한 중요한 정보들이 존재합니다. DB 연결을 위한 계정명과 비밀번호, OAuth 로그인을 위해 인증서버에 요청하기 위한 키 등 중요한 정보들을 공개된 저장소에 올리는 외부 노출행위를 방지해야합니다. 그래서 환경변수로 저장해놓고 사용해야합니다.
NodeJS 프로세스에 대한 정보와 제어를 제공하는 process라는 객체를 지원하고있습니다. process.env라는 명령어를 통해 환경변수에 접근합니다. 이제 알아야할 것은 TypeScript + Express 프로젝트에 환경변수를 어떻게 적용해야하나 입니다. 라이브러리부터 알아봅시다.
dotenv
"@types/dotenv"
cross-env
실제 배포될 앱을 위한 production, 개발 환경에서 활용할 development 등등 NODE_ENV에다가 변수를 담아두고 작업하는 것으로 알고있습니다. 하지만 TypeScript 프로젝트에서 Node_ENV가 없으므로 definition type을 생성해 줘야합니다.
declare namespace NodeJS {
interface ProcessEnv {
readonly NODE_ENV?: 'development' | 'production' | 'test';
}
}
이제 각 타입에 맞는 환경변수 파일들을 생성해줍니다.
IM=develop
PORT=
HOST=
GITHUB_ID=
....
IM=prod
PORT=
HOST=
GITHUB_ID=
....
IM=test
PORT=
HOST=
GITHUB_ID=
....
동적인 환경변수는 보통 동일 OS에서만 사용이 가능합니다.
"prod": "NODE_ENV=production nodemon --exec ./dist/src/server.js",
"dev": "NODE_ENV=development nodemon --exec \"ts-node\" ./src/server.ts
예를 들어, MacOS에서 환경변수를 이렇게 가져다 쓰면, Windows나 Linux에서도 동일한 설정으로 환경변수에 접근하기위해 cross-env를 사용해줍니다.
"prod": "cross-env NODE_ENV=production nodemon --exec ./dist/src/server.js",
"dev": "cross-env NODE_ENV=development nodemon --exec \"ts-node\" ./src/server.ts"
이제 src/Config/ 디렉토리안에 .env.production, .env.development, .env.test 파일을 가져와야합니다.
제가 작성한 코드는 다음과 같습니다.
import { config as configENV } from 'dotenv';
import { resolve } from 'path';
const root: string = `${process.cwd()}/src/.env/`;
console.log(process.env.NODE_ENV);
switch (process.env.NODE_ENV) {
case 'development':
configENV({
path: resolve(root + '.env.development'),
});
break;
case 'production':
configENV({
path: resolve(root + '.env.production'),
});
break;
case 'test':
configENV({
path: resolve(root + '.env'),
});
default:
throw new Error(`NODE_ENV: ${process.env.NODE_ENV}를 불러올 수 없습니다.`);
}
interface ThirdENV {
[key: string]: number | string | undefined;
}
export const MySqlENV: ThirdENV = {
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PWD,
port: Number(process.env.MYSQL_PROT),
database: process.env.MYSQL_DB,
};
Switch Case 문법으로 분기를 나눠줍니다.
저는 .env를 다른 루트에 저장하고있기 때문에, dotenv의 config 속성에 있는 path를 활용했습니다.
process.cwd()는 현재위치가 아닌 프로젝트의 루트 디렉토리를 가져옵니다. 덕분에 __dirname보다 환경변수 위치를 가져오는데 좀더 수월했습니다.
interface ThirdENV {
[key: string]: number | string | undefined;
}
export const MySqlENV: ThirdENV = {
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PWD,
port: Number(process.env.MYSQL_PROT),
database: process.env.MYSQL_DB,
};
이부분은 다른 플렛폼이나, 데이터베이스에 접근할 정보를 미리 생성해뒀습니다.