[모잇지] 바닥부터 Webpack 환경 설정하기

유소정·1일 전
1

모잇지

목록 보기
2/2

👋 들어가며

레벨 3 팀 프로젝트에서는 번들러로 Webpack을 사용해야 한다.
그래서 직접 환경 설정을 해보면서 과정을 정리해봤다.


1️⃣ Webpack을 사용하는 이유

Webpack에 대한 이해가 있다면 대부분의 나머지 빌드 도구는 이해가 어렵지 않을 것으로 생각합니다.

Vite 등의 다른 도구를 도입하는 경우가 늘고는 있으나, 아직까지는 프로덕션에서 Webpack 기반으로 이미 구성된 프로젝트가 많은 것으로 판단하였습니다. 이 도구를 사용해 빌드 환경을 직접 구성하고, 프로젝트를 진행하는 과정에서의 트러블 슈팅 경험을 쌓아보기를 권장합니다.


2️⃣ 요구사항

  • Webpack 기반의 React & TypeScript 프로젝트 구조가 구성되어 있고, 실행 및 빌드가 가능하다.
  • Webpack 기반의 프론트엔드 프로젝트를 직접 설정한다.
  • 프론트엔드 리소스 빌드 및 번들링에 필요한 요소를 이해하고 설정할 수 있다.

🔧 Webpack, 환경 설정을 하자

공식문서를 보면 환경 설정을 할 수 있는 방법은 2가지다.
모두 해봤고 비교해봤다.

  1. create 명령어를 이용해서 간단하게 설치하기
  2. 직접 하나하나 설치하기

1️⃣ create 명령어를 이용해서 간단하게 설치하기

  • ⏱ 소요시간: 5분
  • 장점
    • 초기 환경 설정이 없는 상태라면, create 명령어를 이용해서 빠르게 프로젝트를 만들 수 있다.
    • TypeScript 같은 부가적인 도구도 함께 사용할 수 있도록 도와줘서, 따로 설치하거나 Webpack에 해당 도구를 사용한다고 설정할 필요가 없다. 알아서 해준다.
  • 단점
    • 직접 작성하지 않은 코드가 작성된다. 내가 필요한 것보다 더 많은 설정이 되어 있을 수도 있다.
    • 나중에 설정 오류가 발생하면 파악하는데 시간이 걸린다.

2️⃣ 직접 하나하나 설치하기

  • ⏱ 소요시간: 30분
  • 장점
    • 필요한 부분만 설정에 포함하면서 하나씩 쌓아갈 수 있다.
    • 환경에 대한 이해도가 올라간다.
  • 단점
    • TypeScript 같은 추가적인 도구를 쓰려면 따로 설치 및 설정을 해줘야 한다. 다시 말해서, 도구를 설치하고 Webpack에 해당 도구를 사용한다고 설정해야 한다.

⭐️ Webpack 환경 설정하며 겪은 과정 정리

직접 환경 설정(2번 방법)을 해보면서 여러 오류를 마주했고, 그때마다 어떻게 문제를 정의하고 해결했는지 과정을 정리했다.

💫 ReferenceError: require is not defined in ES module scope

[webpack-cli] Failed to load '/Users/.../webpack.config.js' config
[webpack-cli] ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and 'package.json' contains "type": "module". 
To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
  • 문제
    webpack.config.js 파일에서 require를 사용했는데, 내 프로젝트는 "type": "module"로 설정되어 있어 CommonJS 문법이 지원되지 않는 상황이었다. (공식문서에 webpack.config.js 파일이 CommonJS로 작성되어 있었음.)

  • 가설

    1. package.json에서 "type": "module"을 제거해 CommonJS 환경으로 돌린다.
    2. webpack.config.js를 ESM 문법으로 변경한다.
  • 해결
    나는 앞으로도 ESM 환경을 유지할 생각이라 2번 방법을 선택했다.

// webpack.config.js

import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export default {
  entry: './src/index.tsx',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

💫 The 'mode' option has not been set

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value.
  • 문제
    mode 옵션이 빠져 있어서 기본값 production으로 동작하고 있었다.

  • 가설
    webpack.config.js에 mode: "development" 또는 mode: "production"을 명시한다.

  • 해결
    mode를 추가해 해결!

export default {
  entry: './src/index.tsx',
  mode: 'production', // mode 설정
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

💫 You may need an appropriate loader to handle this file type (1)

ERROR in ./src/index.tsx 5:51
Module parse failed: Unexpected token (5:51)
You may need an appropriate loader to handle this file type...
  • 문제
    적절한 loader가 없어서 .tsx 파일을 해석하지 못하는 상황이었다.

  • 가설
    에러 메시지에 있는 Webpack 가이드에 나온 대로 html-webpack-plugin을 추가해본다.
    이 플러그인은 HTML 파일을 자동 생성하고, 빌드된 JS를 삽입해준다.

  • 해결
    플러그인을 설치하고 설정했다.

npm install --save-dev html-webpack-plugin
import HtmlWebpackPlugin from 'html-webpack-plugin';

export default {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
  ],
};

✅ html-webpack-plugin은 왜 쓰나?

Webpack으로 번들링을 하면 main.js 같은 결과물이 나오지만, 이 파일을 직접 HTML에 <script src="main.js">로 넣어줘야 브라우저가 실행할 수 있다. 그런데 실제 프로젝트에서는 빌드할 때마다 번들 파일 이름이 바뀌거나 해시값(main.9f8a7b.js)이 붙는 경우가 많아 일일이 HTML을 수정하기 번거롭다. html-webpack-plugin은 이런 과정을 자동화해준다. 템플릿 HTML을 기반으로 최신 JS/CSS 파일을 자동으로 삽입해주고, 빌드할 때마다 새로운 파일명을 알아서 반영하기 때문에 개발자 입장에서 따로 신경 쓸 필요가 없다.


💫 You may need an appropriate loader to handle this file type (2)

  • 문제
    위 플러그인을 추가했는데도 여전히 같은 오류 발생.
    TypeScript 파일이라서 적절한 loader가 필요했다.

  • 가설
    ts-loader를 추가하면 .tsx 파일을 처리할 수 있을 것이다.

  • 해결
    TypeScript 관련 설정을 추가했다.

npm install --save-dev ts-loader typescript
export default {
  module: {
    rules: [
      { test: /\.tsx?$/, use: 'ts-loader', exclude: /node_modules/ },
    ],
  },
};

✅ Webpack만 단독으로 쓰면?

Webpack은 기본적으로 번들러다. 여러 JS 파일을 하나로 합쳐서 브라우저가 읽을 수 있는 파일로 만들어주는 역할을 한다. 하지만 이때 TypeScript(.ts, .tsx) 파일은 처리하지 못한다. 왜냐하면 Webpack은 JavaScript만 이해하기 때문이다. TypeScript를 그대로 번들링하려 하면 에러가 발생하고 멈춘다. 그래서 TypeScript를 JavaScript로 변환해주는 '트랜스파일러'가 필요하다.

✅ ts-loader는 뭘 해주나?

이 역할을 하는 게 바로 ts-loader다. ts-loader는 Webpack이 TypeScript 코드를 이해하고 번들링할 수 있도록 도와주는 Webpack 로더다. 내부적으로는 TypeScript 컴파일러(tsc)를 호출해 두 가지 일을 한다:
1. 트랜스파일링 – TypeScript를 JavaScript로 변환
2. 타입 검사 – 코드에 타입 에러가 없는지 검증
즉, ts-loader는 Webpack의 로더이면서 동시에 TypeScript 변환기(트랜스파일러) 역할도 한다.

✅ 그럼 Babel은?

꼭 ts-loader만 써야 하는 건 아니다. Babel도 사용할 수 있다. Babel은 원래 최신 JavaScript(ES6+) 문법을 구버전 JS로 변환하는 도구인데, 여기에 @babel/preset-typescript 플러그인을 추가하면 TypeScript 문법도 제거할 수 있다. 하지만 Babel은 타입 검사를 하지 않고, 문법만 제거해서 JS로 바꾼다. 타입 에러가 있어도 그냥 넘어간다는 점이 ts-loader와의 중요한 차이다.

✅ ts-loader와 Babel을 같이 쓸 수도 있다

ts-loader로는 타입 검사만 하고(transpileOnly: true), Babel로는 최신 문법 변환과 polyfill 처리를 맡기는 방식이다. 이렇게 하면 타입 안정성과 빠른 빌드 속도를 동시에 잡을 수 있다. (ts-loader로 타입 검사와 트렌스파일링을 모두 하게 되면 빌드 속도가 느릴 수 있기 때문이다.)


💫 you need to install: 'webpack-dev-server' package

[webpack-cli] For using 'serve' command you need to install: 'webpack-dev-server' package.
  • 문제
    webpack-dev-server가 없어 npx webpack serve 명령어가 동작하지 않았다.

  • 가설
    webpack-dev-server를 설치하면 해결될 것 같다.

  • 해결
    설치 후 바로 정상 작동.

npm install --save-dev webpack-dev-server

✅ webpack-dev-server는 왜 쓰나?

webpack-dev-server는 개발 중 코드가 바뀔 때마다 자동으로 번들링하고 브라우저를 새로고침해주는 개발용 서버다. Webpack으로만 작업하면 코드가 바뀔 때마다 새 파일을 만들고 저장소에 저장한 뒤, 브라우저가 그 파일을 다시 불러와야 한다. 이 과정이 느릴 수 있는데, webpack-dev-server는 번들 파일을 저장소에 파일로 쓰지 않고 컴퓨터의 메모리에만 잠깐 올려서 브라우저에 바로 전달하기 때문에 훨씬 빠르다.


🍵 마무리

이전 미션에서는 Vite만 써왔던 터라, Webpack을 설치해보니 설정할 것이 더 많다는 걸 느꼈다. 덕분에 오류도 계속 발생했고 단순히 초기 세팅을 넘어서, 오류가 발생했을 때 문제를 정의하고 가설을 세우고 해결해나가는 사이클을 경험할 수 있었다. 개인적으로는 React 코드에서 발생하는 에러보다 이런 환경 설정 오류를 해결하는 과정이 더 어렵게 느껴졌다.

추가로,
Webpack 외의 도구는 TypeScript, ESLint, Prettier, React를 설치하는 가이드 문서를 참고해서 설치했다.

profile
기술을 위한 기술이 되지 않도록!

0개의 댓글