개요

지금까지 리액트와 Next.js로 수행했던 프로젝트들에서는 리액트와 Next.js에서 자체적으로 빌드 과정을 자동화해주는 방식을 이용해서 프로젝트를 진행했었다. 리액트에서는 CRA 또는 Vite라는 번들링 개발 툴을 이용하여 편리하게 개발할 수 있었으며, Next.js에서는 자체적으로 SWC를 사용하여 컴파일을 진행하며, 번들링은 Webpack을 이용하지만, 개발서버에 한하여 Turbopack을 이용할 수 있었다. 특히, 요즘 추세로는 리액트로 개발할 경우, Vite가 esbuild를 사전 번들링 시에(개발환경), rollup(프로덕션 환경)을 실제 번들링 시에 사용하여 webpack보다 속도에서 큰 장점을 가져 많이 사용된다. 이렇게 편리하고 빠른 번들링과 트랜스파일링 관련 툴들이 있지만, 이렇게 프로젝트를 진행하면서 프론트엔드 개발과정에서의 번들링과 트랜스파일링과 같은 핵심적인 내부 프로세스를 몸소 경험할 수 없어 내부 동작 방식에 대해 궁금증이 생겼었다. 이에 따라서 다음 프로젝트에서는 직접 configuration을 진행하여 번들링과 트랜스파일링 관련 설정을 구성할 수 있는 webpack과 babel을 사용하여 이 내부 동작 과정을 깊게 이해하고 싶었다. 이 블로그 글에서는 webpack, babel, react, typescript를 이용한 프로젝트 초기 세팅을 하는 과정을 작성해보며 학습 및 기록을 남기고자 한다.

webpack

webpack에서는 보통 development 환경과, production 환경을 나누어서 개발을 진행한다. 따라서 webpack.common.js에서는 공통된 설정을, webpack.dev.js에서는 development환경에서만 사용되는 설정을, webpack.prod.js에서는 production환경에서만 사용되는 설정을 구성하여 환경을 나누어 설정해주었다. 이후, package.json의 scripts 설정에서 각 환경마다 적용이 되어야 하는 config 파일을 참조하게끔 설정해주면 각 환경에 맞는 설정이 적용된다.

"scripts": {
    "start": "webpack serve --config webpack.dev.js --progress",
    "build:prod": "webpack --config webpack.prod.js --progress",
    "build:dev": "webpack --config webpack.dev.js --progress",
  },
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const dotenv = require('dotenv');

dotenv.config();

module.exports = {
  entry: './src/index.tsx',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, './dist'),
    publicPath: '/',
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\\.(png|svg|jpg|jpeg|gif|webp)$/i,
        type: 'asset/resource',
      },
      {
        test: /\\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\\.(ts|js)x$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html',
    }),
    new webpack.DefinePlugin({
      'process.env': JSON.stringify(process.env),
    }),
  ],
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
    },
  },
};

우선, entry는 webpack이 번들링을 진행할 진입 파일을 지정하는 설정이다. 기존 리액트 프로젝트와 같이 react관련 초기 진입점인 createRoot 및 React.StrictMode를 설정하는 곳이다. index.tsx가 해당 파일이 된다.

output은 번들링된 결과가 담긴 파일에 대한 설정을 지정하는 옵션이다. 이 옵션 내의 publicPath는 브라우저 url에서 내 프로젝트 asset이 참조되어야 하는 장소를 명시하는 것이다. 내가 설정한 것과 같이 public: ‘/’로 설정하면, 이는 asset들이 루트 url에서 참조된다는 뜻이다. 번들된 파일이 서버의 url의 루트를 기준으로 참조되어야 하니 해당 옵션이 필요하다. 한 예로, 만약에 CDN에서 asset이 참조되어야 하는 경우에는 publicPath를 CDN url로 설정해주면 된다.

ouput의 clean옵션은 빌드 후에 필요한 파일만을 dist 폴더 내에 남기고 필요없는 파일은 지우는 역할을 한다.