나에게 쓰는 기록들

현재 배우는 것이 무엇이든 글로 써서 기록을 남기는 것은 가치가 있다. - 소프트웨어 장인

Web

Webpack5 환경 설정하기

그리무 2021. 11. 1. 21:41
 

우리는 Webpack이 왜 필요할까?

본 글은 2020년에 작성된 글입니다. 프론트엔드 개발 중이라면 Webpack이라는 기술에 대해 필수적으로 마주치게 된다. 이번 포스팅은 Webpack이 무엇인지, 왜 필요한지에 대해 찬찬히 알아보려한다. W

seogeurim.tistory.com

지난 포스팅에서 Webpack이 무엇이며 왜 쓰는지에 대해 알아보았다. 다시 한 번 그 내용을 정리하자면 다음과 같다.

  • Webpack은 모듈 번들러이다.
  • 프로젝트 규모가 커지고 JavaScript가 발전(모듈 시스템)하면서 요청하는 파일들이 많아졌다.
  • 그 많은 파일들을 모듈 번들러가 합쳐서 요청하는 파일의 수를 줄일 수 있다.
  • 번들(합쳐진 파일)이 너무 커진다면 초기 로딩 속도가 느려지는 문제가 발생할 수 있고, 청크, 캐시, 코드 스플릿 등을 도입해 해결할 수 있다.

이번 포스팅에서는 이러한 Webpack을 적용해 간단한 환경을 설정하는 법에 대해 알아보려 한다.

 


Webpack 환경 구성

우선 사용할 Webpack의 버전은 다음과 같다. (Webpack v5)

"webpack": "^5.44.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"

Webpack은 버전별로 설정하는 방법이 조금씩 다를 수 있으니 버전에 따른 문서를 확인하는 것이 중요하다.

 

우선 devDependency로 webpack, webpack-cli, webpack-dev-server를 추가해준다.

yarn add webpack webpack-cli webpack-dev-server -D
// or
npm install webpack webpack-cli webpack-dev-server --save-dev

webpack.config.js

webpack.config.js 파일은 webpack 옵션들을 설정할 수 있는 파일이다. webpack 명령어가 실행되면 해당 파일을 읽어 그 내용으로 빌드를 진행한다. Webpack v4부터는 config 파일을 설정하지 않는다면 디폴트 설정값으로 빌드한다고 한다.

// webpack.config.js
const path = require('path');

module.exports = {
  entry: {
    app: './src/index.js',
  },
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.js',
  },
};
  • entry : webpack이 번들링할 때는 특정 지점에서부터 파일 간의 의존성을 찾아가며 번들링한다. entry는 그 '특정 지점', 즉 번들링의 시작점을 말한다.
  • output : 번들링한 결과물을 어디로 내보낼지 지정한다. 위와 같이 설정할 경우 메인 결과물인 bundle.js'./dist/bundle.js'에, 그 외 파일은 ./dist 폴더에 보내진다.

가장 기본적인 entry와 output 옵션을 시작으로 다양한 옵션들에 대해 알아보자.

mode

production, development 등 환경에 따라 다른 webpack 설정을 적용하고 싶다면 다음과 같은 방법이 있다.

  • webpack --config webpack.config.[envname].js : 특정 이름의 config 파일을 가지고 번들링한다.
  • webpack --mode=production : webpack 명령어 실행 시 mode 플래그를 준다.
  • config 파일에 mode를 명시한다. 
  • module.exports = { mode: 'development', //...​

production(default), development, none 의 세 가지 mode 옵션이 존재한다.

loader

loader를 설정해주지 않으면 webpack은 JavaScript와 JSON 파일만 번들링한다. 다른 형식의 파일들을 번들링하기 위해서 loader를 사용한다.

module: {
  rules: [
    {
      test: /* 설정한 파일 형식에 대한 정규식 */,
      use: {
        loader: '로더의 이름',
        options: {
          /* 로더 옵션 설정 */
        },
      },
      exclude: /* 컴파일에서 제외할 내용 */,
    },
  ],
},

위 형식으로 loader를 설정해주면 된다. webpack은 entry부터 번들해 나가면서 test에 작성한 정규식에 해당하는 파일을 찾으면 loader에 적용하게 된다.

plugins

plugins를 통해 Webpack 설정과 관련된 플러그인을 설치하고 도입할 수 있다.

html-webpack-plugin 플러그인을 활용하면 모든 번들을 포함하는 HTML 문서를 자동으로 생성할 수 있다.

//...
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
  ],
  //...
};

위와 같이 작성한 후 빌드해보면 bundle.js를 스크립트 파일로 포함하는 index.html 파일이 output path에 생성된다.

sourceMap

빌드 후 개발자 도구를 열어 확인해보면 디버깅 시 bundle.js 코드를 확인해야 하는 것을 알 수 있다. 즉 디버깅이 불가능하다.

sourceMap이란 빌드한 파일과 원본 파일을 서로 연결시켜주는 기능이다. sourceMap 설정을 통해 bundle.js 코드의 특정 부분이 원본 코드의 어떤 부분인지 확인할 수 있고, 그를 통해 디버깅을 수행할 수 있다.

devtool: 'eval-cheap-source-map'

위와 같이 설정할 수 있고 소스 맵 설정 옵션 비교표를 통해 팀에 알맞은 설정을 적용하면 된다.

devServer

Webpack을 사용해 [빌드 후 실행, 코드 수정 후 빌드 후 실행, ...] 과정을 반복하면 개발 시 매우 불편할 것이다. webpack-dev-server를 사용하면 이 문제를 해결할 수 있다. devServer를 통해 로컬 서버를 열어 코드를 수정했을 때 다시 빌드하고, 핫리로드를 적용해 바로바로 빌드 결과를 확인할 수 있다.

devServer: {
  contentBase: path.resolve(__dirname, './dist'),
  compress: true,
  hot: true,
  port: 9000,
},

위와 같이 devServer에 여러 설정들을 추가할 수 있다. 추가 설정을 살펴보고 팀에 알맞은 설정을 적용하면 된다.

devServer는 webpack serve 명령어를 통해 실행할 수 있고, "dev": "webpack serve --mode development --open"와 같이 package.json에 script를 작성해두는 것이 좋다.

 

환경 설정 중 이런 오류가 난다면?

Webpack을 처음 다뤄볼 때, 다음의 오류에 고민을 했던 경험이 있어서 남겨본다.

1. output.path에 상대 경로를 썼을 때

에러 내용 : configuration.output.path: The provided value '../dist' is not an absolute path!

path에는 절대 경로를 써야 하고, 그를 위해 path.join() 또는 path.resolve() 메서드를 사용하면 된다.

두 메서드의 차이점은 /에 대한 처리 방식에 있다. join 메서드는 /를 만나도 계속 연결하여 경로를 만들고, resolve 메서드는 /를 만나면 절대경로로 인식하여 이전 경로를 모두 무시한다.
  path.join('/a', '/b') // Outputs '/a/b'
  path.resolve('/a', '/b') // Outputs '/b'​

2. loader 작성 중 module.rules.use.loader에 ['babel-loader']로 작성했을 때

에러 내용 : configuration.module.rules[0].use.loader should be a non-empty string.

loader는 배열이 아니라 string으로 작성하여야 한다.

3. webpack-dev-server로 실행했을 때 프로젝트가 수정되면 자동 빌드되어 보여져야 하는데, 그렇지 않았다.

처음에 index.html을 public 디렉토리에 두고 그 파일 내에 <script>로 번들된 파일의 경로를 명시했었다. 이 경우 build했을 때는 문제가 되지 않았지만 devServer로 실행 시에는 수정 내역이 리로드되지 않는 문제가 발생하였다.

devServer의 번들된 결과물은 따로 저장되지 않고 메모리에 저장된다. 따라서 그 경로에 차이가 있지 않을까라는 추측을 하게 되었고, html-webpack-plugin 플러그인을 활용해 번들된 파일이 index.html에 자동으로 연결되도록 하여 해결할 수 있었다.

 

나만의 boilerplate를 만들어보자!

Webpack에 대해 어느 정도 이해했다면 프로젝트 기술에 알맞게 나만의 boilerplate를 만들어보는 것을 추천한다. 아래는 내가 생성한 boilerplate들이다. 이 포스팅을 읽었다면 한 번씩 구경오시길!!

 

 

GitHub - Seogeurim/webpack-es6-boilerplate: A minimal webpack 5 boilerplate 🌐

A minimal webpack 5 boilerplate 🌐. Contribute to Seogeurim/webpack-es6-boilerplate development by creating an account on GitHub.

github.com

 

GitHub - Seogeurim/react-typescript-boilerplate: React X TypeScript boilerplate 🌐

React X TypeScript boilerplate 🌐. Contribute to Seogeurim/react-typescript-boilerplate development by creating an account on GitHub.

github.com

GIVEME-STAR

🌟


참고 자료

웹팩-Webpack-의-개념과-vanilla-js-boilerplate

Node path.join() vs path.resolve()

What's the difference between path.resolve and path.join?

웹팩 데브 서버(webpack-dev-server) 3버전(feat. proxy)