dotenv를 사용한 NodeJS 환경변수 설정과 Webpack 번들로 환경변수 전달하기

Explanation

다시 찾아온 주말을 맞이하여,
오늘은 간단하게 노드 환경 변수를 설정하고, Webpack을 사용해서 프로젝트의 번들을 만들 때 환경 변수도 함께 전달해서 처음 커맨드에 따라서 코드가 자동 분기될 수 있도록?? 하는 방법에 대해 적어보려 합니다.

간단한 샘플 코드는 깃헙의 저장소에 올려놓았습니다.
https://github.com/falsy/blog-post-example/tree/master/dotenv-webpack-front-end
웹팩에 대한 기본적인 이해가 있다는 것을 가정하며, 웹팩은 v4을 사용합니다 :)

1. dotenv 설치

$ npm install --save-dev dotenv

dotenv는 .env 파일로 간단하게 노드의 환경 변수를 설정할 수 있도록 도와주는 패키지랍니다.
아래와 같이 간단하게 사용할 수 있답니다.

// 예. 디렉토리 구조
/node_modules
.env
app.js
package.json
// .env
HELLO="WORLD"
// app.js
const dotenv = require('dotenv');

dotenv.config();
console.log(process.env.HELLO);
// WORLD

위와 같이 그냥 .config() 메서드를 실행하면 프로젝트 root 디렉토리의 .env 파일을 찾아서 파일의 내용을 환경 변수로 등록해주고, process.env.XXX로 호출해서 사용할 수 있답니다.

// app.js
dotenv.config({
  path: './env/server.env'
});

그리고 위와같이 config에 path 속성으로 .env 값의 경로나 파일을 지정해 줄 수도 있답니다.

저는 root 디렉토리에 env 라는 디렉토리를 만들고 거기에 'local.env' 그리고 'server.env' 이렇게 두개의 파일 만들고 환경 변수는 아래와 같이 작성하였어요.

// env/local.env
API_URL="http//localhost"
// env/server.env
API_URL="https//falsy.me"

2. 웹팩 CMD로 옵션값 받아오기

보통 package.json의 scripts에 'start', 'test', ... 등 많이 등록해서 사용하잖아요??
저는 거기에서 앞서 설정한 local과 server로 분기 처리되게 할거에요.
저는 아래와 같이 작성하였습니다.

// package.json
...
"scripts": {
  "local": "webpack-dev-server --mode development --stage local",
  "server": "webpack-dev-server --mode development --stage server"
},
...

그러면 이제 'npm run local'과 'npm run server' 커맨드를 사용할 수 있겠죠??
그리고 둘 모두 개발 모드이고, 뒤에 --stage 라는 이름은 제가 임의로 명명한거에요.
다음으로 webpack.config.js 파일은 아래와 같이 작성하였습니다.

// webpack.config.js
const webpack = require('webpack');
const HTMLWeebPackPlugin = require("html-webpack-plugin");
const dotenv = require('dotenv');

module.exports = (env, options) => {
// 여기서 첫번째 인자인 env는 아까 위 커맨드에서 --env 이후 값으로 받아올 수 있고
// 그다음 options는 추가적으로 설정한 값들을 받아올 수 있습니다.
// 전 여기서 --stage 라는 값을 사용했으니까 options.stage 로 해당 값을 받아올 수 있겠죠??

  dotenv.config({
    path: `./env/${options.stage || 'server'}.env`
  });
  // 이제 아까 설치했던 dotenv에 config 메서드를 실행해주고
  // env파일의 경로를 env폴더의 options로 받은 stage의 값의 이름으로 된
  // .env 파일('./env/local.env' 또는 './env/server.env') 의 환경 변수를 등록합니다.

  console.log(process.env.API_URL);
  // 이렇게 콘솔을 찍어본다면,
  // 'npm run local'로 실행했다면, 'http//localhost'가 출력되고
  // 'npm run server'로 실행했다면, 'https//falsy.me'가 출력되겠죠?

  return {
    plugins: [
      new HTMLWeebPackPlugin({
        template: "./src/index.html",
        filename: "./index.html"
      }),
      new webpack.DefinePlugin({
        'process.env.API_URL': JSON.stringify(process.env.API_URL)
      }),
      new webpack.EnvironmentPlugin(['API_URL'])
    ]
  };
};

3. 클라이언트에서도 환경 변수 값을 받아 사용하기

이번 순서는, 앞에 작성 했던 webpack.config.js 파일의 뒷부분이에요.

// webpack.config.js

  ...

  return {
    plugins: [
      new HTMLWeebPackPlugin({
        template: "./src/index.html",
        filename: "./index.html"
      }),

      // 여기 아래부분의 두개의 플러그인 인데요.
      // DefinePlugin으로 'process.env.API_URL'를 process.env.API_URL 이라는 환경변수를 정의하고
      new webpack.DefinePlugin({
        'process.env.API_URL': JSON.stringify(process.env.API_URL)
      }),
      // EnvironmentPlugin 이 뒤에 []에 해당하는 환경변수를 클라이언트로 전달해 준답니다.
      new webpack.EnvironmentPlugin(['API_URL'])
    ]
  };
};

그러면 이제 클라이언트에서 동작할 코드로 가서 확인을 해보면!

// ./src/index.js
console.log(process.env.API_URL);
// 'npm run local'로 실행했다면 : 'http//localhost'
// 'npm run server'로 실행했다면 : 'https//falsy.me'

끝