2 minute read

이 글은 프론트엔드 크루 노아가 작성했습니다.

지금까지 하나의 파일(webpack.config.js)에서 환경(dev, prod)에 대한 웹팩을 설정하였다. 환경에 따른 분리가 필요하면 삼항연사자를 사용한다. 아직은 파일이 크지 않아 삼항연산자도 충분하다. 하지만 앞으로 설정이 많아지고 복잡해지면 삼항연산자로 인한 환경 구분은 상당히 피로감을 줄 수 있다. 때문에 환경에 따라 파일을 분리하는 것이 효율적이다. 웹팩으로 리액트 시작하기 네 번째 파트에서는 환경에 분리하여 웹팩을 설정하는 과정을 다룬다.

다음의 글은 웹팩 공식문서를 참고하여 작성했다.

[Production 웹팩](https://webpack.kr/guides/production/)

1. 파일 분리하기

다음의 파일을 새롭게 생성한다. 이때 파일의 경로는 기존 webpack.config.js의 경로와 동일하다.

  • webpack.common.js: dev, prod 환경에서 공통 설정
  • webpack.dev.js: dev 환경에서의 설정
  • webpack.prod.js: prod 환경에서의 설정

2. webpack-merge 유틸리티

dev환경에서의 웹팩 빌드는 webpack.dev.js파일과 webpack.common.js파일을 함께 사용한다. 때문에 이 둘을 합쳐주는 기능이 필요하다. 이를 쉽게 도와주는 유틸리티가 webpack-merge라이브러리이다. 이를 설치한다.

yarn add -D webpack-merge

https://github.com/survivejs/webpack-merge


3. webpack.common.js

먼저 두 환경에서의 공통 웹펙 설정이다.

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");

// 객체를 내보내는 것이 아니라 함수를 내보낸다. 공식문서에는 객체를 내보낸다.
module.exports = () => {
  return {
    entry: "./src/index.tsx",
    output: {
      filename: "bundle.js",
      path: path.resolve(__dirname, "dist"),
      clean: true,
      publicPath: "/",
    },
    resolve: {
      extensions: [".ts", ".tsx", ".js", ".jsx"],
      alias: {
        // ...
      },
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: ["style-loader", "css-loader"],
        },
        {
          test: /\.(ts|tsx)$/,
          use: {
            loader: "ts-loader",
            options: {
              configFile: path.resolve(__dirname, "tsconfig.json"),
            },
          },
          exclude: /node_modules/,
        },
        {
          test: /\.(png|svg|jpg|jpeg|gif)$/i,
          type: "asset/resource",
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: "public/index.html",
      }),
    ],
  };
};

4. webpack.dev.js, webpack.prod.js

dev환경에서만 필요한 웹팩 설정이다.

// webpack.dev.js

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const Dotenv = require("dotenv-webpack");

module.exports = merge(common(), {
  mode: "development",
  devtool: "eval-source-map",
  devServer: {
    port: 3000,
    historyApiFallback: true,
    hot: true,
  },
  plugins: [
    new Dotenv({
      path: "./env-submodule/.env.development",
    }),
  ],
});

prod환경에서만 필요한 웹팩 설정이다.

// webpack.prod.js

const { merge } = require("webpack-merge");
const common = require("./webpack.common.js");
const Dotenv = require("dotenv-webpack");

module.exports = merge(common(), {
  mode: "production",
  devtool: "source-map",
  plugins: [
    new Dotenv({
      path: "./env-submodule/.env.production",
    }),
  ],
});

mode, devtool, Dotenv의 path의 값은 삼항연산자로 구분했지만 파일을 나누었기 때문에 나누지 않고 dev환경일 때의 값을 넣어주면 된다. 또한 devServer는 prod환경에서는 필요 없기 때문에 설정하지 않는다.

위 두 파일을 살펴보면 webpack-merge유틸리티에서 제공하는 merge함수를 사용하여 webpack.common.js파일과 각각의 환경 파일을 통합하는 것을 알 수 있다. 이때 주의해야 할 점은 다음과 같다.

  1. webpack.common.js에서 함수를 내보낼 경우: common()로 함수를 실행하여 객체를 가져온다.
  2. webpack.common.js에서 객체를 내보낼 경우: common으로 바로 객체를 가져온다.

5. NPM Scripts

마지막으로 환경에 따라 scripts의 명령어를 다르게 설정해야 한다. 다음과 같이 수정한다.

{
  // ...
  "scripts": {
    "prod": "NODE_ENV=production webpack server --open --config webpack.prod.js",
    "dev": "NODE_ENV=development webpack server --open --config webpack.dev.js",
    "build": "yarn test && NODE_ENV=production webpack --config webpack.prod.js"
  }
  // ...
}