icon
14장 : 개발도구와 워크플로우

Babel과 Polyfill

현대 JavaScript 개발은 빠르게 발전하며 ES6(ECMAScript 2015) 이후로 const, let, 화살표 함수(=>), 비동기/대기(async/await), 클래스(class), 스프레드 문법(...) 등 편리하고 강력한 새로운 문법과 기능들이 계속해서 추가되고 있습니다. React, Vue 등 최신 프레임워크와 라이브러리들은 이러한 최신 JavaScript 문법을 적극적으로 활용합니다.

하지만 모든 사용자의 브라우저가 최신 JavaScript 문법을 지원하는 것은 아닙니다. 특히 구형 브라우저나 일부 모바일 브라우저에서는 최신 문법을 인식하지 못하여 웹 애플리케이션이 제대로 동작하지 않는 문제가 발생할 수 있습니다. 이러한 호환성 문제를 해결하기 위해 필수적으로 사용되는 도구가 바로 BabelPolyfill입니다.

이번 장에서는 Babel이 무엇이며 어떻게 최신 JavaScript 코드를 구형 브라우저가 이해할 수 있는 코드로 변환하는지, 그리고 Polyfill이 필요한 이유와 사용 방법에 대해 자세히 알아볼 것입니다. 이들을 통해 여러분은 항상 최신 JavaScript 문법으로 편리하게 개발하면서도, 모든 사용자가 안정적으로 웹 애플리케이션을 이용할 수 있도록 만들 수 있습니다.


Babel 이란?

Babel은 최신 JavaScript (ES2015+) 코드를 구형 JavaScript 환경(주로 ES5)에서 동작할 수 있도록 변환해주는 트랜스파일러(Transpiler) 입니다.

  • Transpiler (트랜스파일러): 소스 코드(Source Code)를 다른 소스 코드(Source Code)로 변환하는 도구를 의미합니다. 컴파일러(Compiler)가 고수준 언어를 저수준 언어(기계어)로 변환하는 것과 구분됩니다.

Babel의 필요성

  • 브라우저 호환성: 모든 브라우저가 최신 JavaScript 문법을 동시에 지원하지 않습니다. Babel은 개발자가 편리한 최신 문법으로 코드를 작성하고, 실제 배포 시에는 넓은 범위의 브라우저에서 동작하도록 변환해줍니다.
  • 생산성 향상: 개발자는 async/await, 화살표 함수 등 생산성을 높여주는 최신 문법을 걱정 없이 사용할 수 있습니다.
  • 프레임워크 지원: React의 JSX 문법(<div>Hello</div>와 같은 HTML 유사 코드)은 JavaScript 표준 문법이 아닙니다. Babel은 JSX를 일반 JavaScript 함수 호출(React.createElement('div', null, 'Hello'))로 변환하여 브라우저가 이해할 수 있도록 합니다.
  • TypeScript 지원: TypeScript 코드를 JavaScript 코드로 변환하는 데도 Babel을 사용할 수 있습니다.

Babel의 동작 방식 (간략)

Babel은 플러그인(Plugins)프리셋(Presets) 이라는 개념을 사용합니다.

  • 플러그인(Plugins)
    • Babel의 가장 작은 변환 단위입니다. 특정 JavaScript 문법 하나를 변환하는 규칙을 정의합니다.
    • 예: babel-plugin-transform-es2015-arrow-functions는 화살표 함수를 일반 함수로 변환합니다.
  • 프리셋(Presets)
    • 여러 개의 플러그인들을 미리 묶어놓은 것입니다. 개발자가 개별 플러그인을 일일이 설정할 필요 없이, 특정 목적(예: 특정 ECMAScript 버전 지원)을 위해 필요한 플러그인들을 한 번에 적용할 수 있게 해줍니다.
    • @babel/preset-env: 가장 널리 사용되는 프리셋입니다. 타겟으로 하는 브라우저 환경(.browserslistrc 파일이나 package.jsonbrowserslist 필드에 명시)에 맞춰 필요한 플러그인들을 동적으로 결정하여 적용합니다. 불필요한 변환을 줄여 번들 크기를 최적화합니다.
    • @babel/preset-react: React의 JSX 문법을 JavaScript로 변환하는 데 사용되는 플러그인들을 포함합니다.
    • @babel/preset-typescript: TypeScript 코드를 JavaScript로 변환하는 데 사용됩니다.

Webpack과 Babel 연동

Webpack 프로젝트에서 Babel을 사용하려면 babel-loader를 설치하고 webpack.config.js에 설정해야 합니다.

설치

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader

.babelrc 파일 생성 루트 디렉토리에 .babelrc 파일을 생성하고 사용할 프리셋을 정의합니다. (이 파일은 babel-loader에 의해 자동으로 로드됩니다.)

// .babelrc
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ]
}

@babel/preset-env는 기본적으로 브라우저 환경을 가정하지만, 더 구체적으로 타겟 브라우저를 명시할 수 있습니다. (예: package.jsonbrowserslist 필드 추가)

// package.json
{
  ...
  "browserslist": [
    "defaults",
    "not IE 11", // IE 11 제외
    "last 2 versions", // 최신 2개 브라우저 버전
    "> 1%" // 점유율 1% 이상 브라우저
  ]
}

webpack.config.js 설정 module.rulesbabel-loader를 추가합니다.

// webpack.config.js (일부)
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.jsx?$/, // .js 또는 .jsx 파일
        exclude: /node_modules/, // node_modules 내부 파일은 변환하지 않음
        use: {
          loader: 'babel-loader',
          // options는 .babelrc 파일로 대체 가능. (없을 경우 여기에 직접 작성)
          // options: {
          //   presets: ['@babel/preset-env', '@babel/preset-react'],
          // },
        },
      },
    ],
  },
  // ...
};

이렇게 설정하면 Webpack이 JavaScript 파일을 번들링하기 전에 babel-loader를 통해 Babel이 최신 문법을 구형 문법으로 변환하게 됩니다.


Polyfill 이란?

Polyfill (폴리필) 은 구형 브라우저가 지원하지 않는 최신 JavaScript 기능(메서드, 객체 등)을 사용 가능한 형태로 구현해 놓은 코드 조각입니다. Babel이 문법(Syntax)을 변환한다면, Polyfill은 코드의 기능(API) 을 제공합니다.

Polyfill의 필요성

  • Babel은 const, 화살표 함수와 같은 문법적(Syntax) 인 부분을 변환합니다.
  • 하지만 Promise, fetch API, Array.prototype.includes 등은 새로운 전역 객체나 메서드(API) 입니다. 이러한 API들은 특정 브라우저 환경에 내장되어 있지 않으면 Babel만으로는 해결할 수 없습니다.
  • Polyfill은 이러한 누락된 API들을 구형 브라우저에서도 동작하도록 "메꿔주는" 역할을 합니다.

Polyfill 사용 방법

가장 흔하게 사용되는 Polyfill은 @babel/polyfill (구 버전) 또는 core-jsregenerator-runtime입니다. 최신 Babel 버전에서는 @babel/polyfill이 deprecated 되었고 core-js를 직접 사용하는 것을 권장합니다.

1. core-jsregenerator-runtime 설치 core-js는 다양한 최신 ECMAScript 기능의 Polyfill을 제공하며, regenerator-runtimeasync/await와 같은 Generator 기반의 비동기 코드를 변환할 때 필요합니다.

npm install --save core-js regenerator-runtime

참고: 이 패키지들은 실제 서비스에서 필요하므로 dependencies에 설치합니다.

2. 엔트리 파일에 Polyfill 임포트 (직접 임포트 방식) 프로젝트의 메인 엔트리 파일(예: src/index.js)의 가장 상단에 필요한 Polyfill을 임포트합니다.

// src/index.js
import 'core-js/stable';          // 모든 안정화된 ECMAScript 기능 Polyfill
import 'regenerator-runtime/runtime'; // async/await (Generator) Polyfill

import React from 'react';
import ReactDOM from 'react-dom/client';
// ... 나머지 코드

이 방식은 필요한 모든 Polyfill 코드를 번들에 포함시키므로, 번들 크기가 커질 수 있습니다.

3. @babel/preset-envuseBuiltIns 옵션 활용 (권장 방식) @babel/preset-envuseBuiltIns 옵션을 사용하면, Babel이 트랜스파일링하는 과정에서 실제로 사용된 최신 JavaScript 기능 중 타겟 브라우저에서 지원하지 않는 것들만 자동으로 Polyfill을 삽입하도록 할 수 있습니다. 이는 번들 크기를 최적화하는 가장 좋은 방법입니다.

  • useBuiltIns: "usage": 가장 권장되는 방식입니다. 코드에서 사용된 기능만 체크하여 필요한 Polyfill을 자동으로 삽입합니다. (따로 import 'core-js' 할 필요 없음)
  • useBuiltIns: "entry": 엔트리 파일에 import 'core-js'를 명시적으로 작성하고, @babel/preset-env가 타겟 브라우저에 맞춰 필요한 Polyfill만 로드합니다. (이 경우 core-js/stable 전체를 임포트하는 것보다 효율적)

.babelrc 설정

// .babelrc
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage", // 사용된 기능에 따라 Polyfill 자동 삽입
        "corejs": { "version": 3, "proposals": true } // core-js 버전 지정 및 proposal 기능 포함 여부
      }
    ],
    "@babel/preset-react"
  ]
}

이 설정은 browserslist 설정과 함께 동작하여, 타겟 브라우저에 따라 필요한 Polyfill만 자동으로 포함시킵니다. 개발자는 import 'core-js/stable' 등을 직접 작성할 필요가 없어집니다.


Babel과 Polyfill의 관계 요약

역할Babel (트랜스파일러)Polyfill (런타임 주입)
대상최신 문법(Syntax)최신 기능/API(Feature/API)
예시화살표 함수, const, let, class, JSXPromise, fetch, Array.prototype.includes, Map
방식코드 자체를 변환하여 구형 문법으로 변경누락된 기능을 구현한 코드를 런타임에 추가
결과문법 오류 해결ReferenceError, TypeError 같은 런타임 오류 해결

함께 사용하는 이유: 대부분의 모던 웹 프로젝트는 최신 JavaScript 문법을 사용하고 새로운 API도 활용하므로, Babel과 Polyfill을 함께 사용하여 브라우저 호환성 문제를 완벽하게 해결해야 합니다. babel-loader@babel/preset-envuseBuiltIns: "usage" 옵션이 이 둘을 효율적으로 통합하여 관리하는 가장 일반적이고 권장되는 방식입니다.


마무리하며

이번 장에서는 모든 브라우저 환경에서 안정적으로 동작하는 웹 애플리케이션을 만들기 위한 핵심 도구인 BabelPolyfill에 대해 학습했습니다.

여러분은 Babel이 최신 JavaScript 문법과 JSX를 구형 브라우저가 이해할 수 있는 코드로 변환하는 트랜스파일러임을 이해했습니다. 또한, Babel의 동작 원리인 플러그인과 프리셋(특히 @babel/preset-env, @babel/preset-react)의 역할을 파악하고, Webpack의 babel-loader를 통해 Babel을 연동하는 방법을 배웠습니다.

이어서, Babel만으로는 해결할 수 없는 최신 JavaScript API 부족 문제를 해결하기 위한 Polyfill의 필요성을 이해하고, core-js를 활용하여 Polyfill을 적용하는 방법을 익혔습니다. 특히, @babel/preset-envuseBuiltIns: "usage" 옵션을 사용하여 필요한 Polyfill만 자동으로 삽입하여 번들 크기를 최적화하는 전략을 살펴보았습니다.

Babel과 Polyfill은 개발자가 최신 JavaScript 문법의 편리함을 누리면서도, 사용자들에게 넓은 범위의 브라우저 호환성을 제공하는 데 필수적인 도구입니다. 이 장에서 배운 지식들을 바탕으로 여러분의 웹 애플리케이션이 어떤 환경에서도 안정적으로 동작할 수 있도록 최적화하시길 바랍니다.