본문 바로가기

코드 디자인 패턴/javascript

바벨 설정 파일 정리

웹팩을 쓰면서 트랜스 파일러로 바벨을 사용하고 있다.

이 때 바벨 사용법과 설정 정보를 정리함.

 

1. 의존성 설치

개발 시 빌드 의존성으로 다음을 설치한다.

npm install -D @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react babel-loader

 

런타임 의존성으로 다음을 설치한다.

npm install @babel/runtime core-js
  • @babel/core
    • Babel의 엔진
    • . babelrc를 불러와 트랜스 파일링 작업을 실행하고 코드를 만드는 본체
  • babel-loader
    • Webpack과 Babel을 연결해주는 중간자.
    • Webpack 실행 시 파일을 babel-loader를 통해 @babel/core에서 실행
  • @babel/preset-env
    • @babel/core의 플러그인
    • 최신 JavaScript 문법을 구버전 JS로 변환하며, 변환 버전을 구체적으로 설정 가능
    • 폴리필을 삽입하지 않으므로, 필요 시 core-js와 함께 사용해야 한다
  • @babel/preset-react
    • @babel/core의 플러그인
    • JSX 문법을 React 코드로 변환.
  • @babel/plugin-transform-runtime
    • 번들링된 코드가 런타임에서 필요한 일부 헬퍼 함수를 직접 작성하는 대신, 공용 런타임(@babel/runtime) 모듈로 추가함
    • 이 작업이 있으면 각 파일마다 헬퍼 함수가 중복으로 생성되지 않음
      예를 들어, Babel이 class를 변환하면 내부에 classCallCheck 같은 헬퍼가 필요한데,
  • @babel/runtime
    • @babel/plugin-transform-runtime이 런타임 때 사용하는 공용 모듈(실행 시점에 필요한 헬퍼 함수, regenerator 등)
    • @babel/plugin-transform-runtime 을 쓸 때 필수
    • 반드시 dependencies에 있어야 함 (devDependencies가 아님)
  • core-js
    • @babel/preset-env 에서 폴리필 모듈 추가 시 사용

@babel/runtime 과 core-js의 관계
@babel/runtime은 바벨로 변환된 코드에서 사용하는 공용 헬퍼함수다.
@babel/plugin-transform-runtime이 없으면 이게 중복될 수 있는데, 이걸 쓰면 공용으로 따로 분리할 수 있다.
core-js는 브라우저에 없는 기능을 추가해주는 폴리필이다.



 

2. 바벨 설정 파일 babel.config.json

아래는 웹 서비스 개발 시 사용

{
  "presets": [
   "@babel/preset-env",  // 최신 js 코드를 구버전 js 코드로 변환
    ["@babel/preset-react", { "runtime": "automatic" }] 
  ],
  "plugins": ["@babel/plugin-transform-runtime"] // 번들링된 코드에서 자주 사용되는 헬퍼 함수를 직접 작성하는 대신 babel-runtime 패키지에서 가져온다.
}

 

구형 브라우저를 지원하는 경우 아래처럼 호환성 설정과 core-js 삽입이 필요하다.

{
  "presets": [
      [
      "@babel/preset-env", // 최신 js 코드를 구버전 js 코드로 변환
      {
        "targets": {
          "browsers": ["last 2 versions", ">= 5% in KR", "not ie <= 11"]
        },
        "modules": false,
        "useBuiltIns": "usage",
        "corejs": "3.37" // 주의. 이 버전은 실제로 설치된 core-js의 버전명에 맞게 쓰세요!
      }
    ],
    ["@babel/preset-react", { "runtime": "automatic" }] 
  ],
  "plugins": ["@babel/plugin-transform-runtime"] // 번들링된 코드에서 자주 사용되는 헬퍼 함수를 직접 작성하는 대신 babel-runtime 패키지에서 가져온다.
}

 

 

아래는 SDK 개발 시 사용 (다른 쪽에서 빌드 산출물을 소비하는 경우)

{
  "presets": [
    [
      "@babel/preset-env", // 최신 js 코드를 구버전 js 코드로 변환
      {
        "modules": false, // ES6 모듈 문법을 변환하지 않음. 웹팩이 처리하므로 상관 없을 것 같으나 안전용
        "useBuiltIns": false //(기본 값) core-js 폴리필을 자동으로 추가하지 않음. 사용자가 빌드 환경에 맞게 직접 추가해야 함
      }
    ]
  ],
  "plugins": ["@babel/plugin-transform-runtime"] // 번들링된 코드에서 자주 사용되는 헬퍼 함수를 직접 작성하는 대신 babel-runtime 패키지에서 가져온다.
}
  • preset-env
    • target
      • 어떤 브라우저 환경을 지원할지 설정
      • 지금 값은 최신 브라우저 위주 지원
      • 이 설정 값에 따라 es 버전 몇까지 폴리필을 지원할지 결정함 (지금은 대강 es6 수준)
    • modules
      • 바벨이 소스 코드의 모듈 방식을 esm에서 commonJS로 변환할지 여부 
        • 기본값 "auto" → 대부분 CommonJS로 바뀜 (false 아님!)
        • "modules": false → ESM 유지 (Webpack이 최적화 가능)
        • "modules": commonjs" → CommonJS로 변환 (트리쉐이킹 불가)
      • 웹팩과 함께 babel-loader로 쓰는 경우에는, 웹팩에서 소스 코드가 esm이어야 트리셰이킹을 할 수 있으므로, babel-loader 내부적으로 이 값을 false로 처리한다.

      • 그러니 굳이 false를 명시할 필요는 없지만, 혹시 몰라서 명시함
    • useBuiltIns
      • core-js를 이용한 폴리필 삽입 여부를 결정한다.
      • false(기본 값)
        • 폴리필 삽입 기능 비활성화
      •  entry
        • 개발자가 수동으로 소스 코드에 import "core-js/stable"; 을 추가해야함.
        • 그러면 바벨이 필요한 거에 맞게 import 변경
      •  usage
        • 바벨이 코드를 분석해서 자동으로 필요한 폴리필만 import
    • core-js
      • 사용하는 core-js 모듈의 버전 명시
@babel/preset-env와 core-js의 관계
babel-preset-env는 신형 문법을 호환 대상 브라우저에 맞게 구형 문법으로 변환한다.
예컨대 const를 var로 바꾼다던지 말이다.

하지만 어떤 문법은 호환 대상 브라우저에 아예 없는 기능이다.
Promise, Map, 그리고 iterator 관련 기능들처럼 말이다.

이런 내장 모듈은 단순 변환으로 만들 수 없어서 아예 대체용 모듈 코드를 삽입해야 하는데, 이를 폴리필이라 부른다.
babel-preset-env에는 폴리필 모듈이 없다. 대신 어떤 폴리필이 필요할지 코드를 읽어 판단하고 core-js 라는 외부 라이브러리를 써서 삽입한다.

예컨대
소스코드가 이렇다면
[1, 2, 3].includes(2);


useBuiltIns:"usage" 모드에서는 아래처럼 변환된다.

import "core-js/modules/es.array.includes";
[1, 2, 3].includes(2);

 

 

 

3. webpack.config.js에 바벨 모듈(babel-loader)을 추가한다.

아래 module을 추가하면 된다.

위치는 entry이나 output같은 주요 속성과 동일한 계층에 추가하면 순서는 상관없다.

    module: {
      rules: [
        {
          test: /\.(js|jsx)$/, //.js, .jsx 확장자에 대해
          exclude: /node_modules/,
          use: [
          
            {
              loader: "babel-loader", // JavaScript 변환을 위한 Babel 로더
            },
          ],
        },
      ],
    },