🚀 94sssh
Published on

2024.10.31

[딥다이브] - 49. Babel과 Webpack을 이용한 ES6+/ES.NEXT 개발 환경 구축

ES6를 지원하지 않는 IE 환경 등 구형 브라우저에서 문제 없이 동작시키기 위해 트랜스파일러모듈 번들러 등을 사용한다. 또한 다음과 같은 이유로 ESM보다는 별도의 모듈 로더를 사용하는 것이 일반적이다.

  • IE를 포함한 구형 브라우저는 ESM을 지원하지 않음
  • ESM을 사용해도 트랜스파일링이나 번들링이 필요
  • ESM이 지원하지 않는 기능 등 이슈가 존재

49.1. Babel

트랜스파일러인 Babel을 사용하면 ES6의 화살표 함수나 ES7의 지수 연산자 등을 ES5 사양으로 변환해 준다.

// ES6+
;[1, 2, 3].map((n) => n ** n)

// ES5
;[1, 2, 3].map(function (n) {
  return Math.pow(n, n)
})

49.1.2. Babel 프리셋 설치와 babel.config.json 설정 파일 작성

Babel을 사용하려면 @babel/preset-env를 설치해야 한다. 이는 함께 사용되어야 하는 Babel 플러그인을 모아 둔 것으로 Babel 프리셋이라 한다. Babel이 제공하는 공식 Babel 프리셋은 다음과 같다.

  • @babel/preset-env
  • @babel/preset-flow
  • @babel/preset-react
  • @babel/preset-typescript

설치가 완료되면 루트 폴더에 babel.config.json파일을 만들고 작성한다.

{
  "presets": ["@babel/preset-env"] // 해당 프리셋을 사용하겠다는 의미
}

49.1.3. 트랜스파일링

package.json에 scripts를 추가하여 Babel CLI 명령어를 등록해 사용할 수 있다.

{
  "scripts": {
    "build": "babel src/js -w -d dist/js"
  }
}
  • -w: 타깃 폴더에 있는 모든 자바스크립트 파일의 변경을 감지해 자동으로 트랜스파일 (--watch 옵션의 축약형)
  • -d: 트랜스파일링된 결과물이 저장될 폴더를 지정, 지정된 폴더가 없다면 자동 생성 (--out-dir 옵션의 축약형)

49.1.4. Babel 플러그인 설치

별도의 플러그인이 필요하다면 설치 후 사용한다. 플러그인은 Babel 홈페이지에서 검색할 수 있다. 설치한 플러그인은 babel.config.json에 추가한다.

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

49.1.5. 브라우저에서 모듈 로딩 테스트

Node.js 환경에서 CommonJS 방식의 모듈 로딩 시스템을 따른다면 문제 없지만, 브라우저는 CommonJS 방식의 require 함수를 지원하지 않는다. 트랜스파일링된 결과를 브라우저에서 실행하면 에러가 발생한다. Webpack을 통해 문제를 해결할 수 있다.

49.2. Webpack

Webpack은 의존 관계에 있는 자바스크립트, CSS, 이미지 등의 리소스들을 하나(또는 여러 개)의 파일로 번들링하는 모듈 번들러다. 의존 모듈이 하나의 파일로 번들링되므로 별도의 모듈 로더가 필요 없다. HTML 파일에서 script 태그로 여러 개의 자바스크립트 파일을 로드하는 번거로움도 사라진다.

49.2.2. babel-loader 설치

Webpack이 모듈을 번들링할 때 Babel을 사용해 트랜스파일링하도록 babel-loader를 설치한다.

이후 npm scripts를 변경해 Babel 대신 Webpack이 실행되도록 수정한다.

{
  "scripts": {
    "build": "webpack -w"
  }
}

49.2.3. webpack.config.js 설정 파일 작성

webpack.config.js를 생성하고 작성한다.

const path = require('path')

module.exports = {
  entry: './src/js/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/bundle.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [path.resolve(__dirname, 'src/js')],
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: ['@babel/plugin-proposal-class-properties'],
          },
        },
      },
    ],
  },
  devtool: 'source-map',
  mode: 'development',
}

이제 트랜스파일링은 Babel이 수행하고 번들링은 Webpack이 수행한다. dist/js 폴더에 생긴 bundle.js를 index.html에서 불러와 브라우저에서 실행할 수 있다.

<!doctype html>
<html>
  <body>
    <script src="./dist/js/bundle.js"></script>
  </body>
</html>

49.2.4. babel-polyfill 설치

ES6에 추가된 기능(Promise, Object.assign, Array.from 등)을 ES5 사양으로 대체할 기능이 없다면 트랜스파일링되지 못한다. 구형 브라우저에서도 지원해주려면 @babel/polyfill을 설치한다.

@babel/polyfill은 개발 환경만이 아니라 실제 운영 환경에서도 사용해야 하므로 개발용 의존성으로 두지 않는다. --save-dev 옵션을 지정하지 않는다.

webpack.config.js파일의 entry 배열에 폴리필을 추가한다.

module.exports = {
  entry: ['@babel/polyfill', './src/js/main.js'],
}