Babel과 Polyfill
현대 JavaScript 개발은 빠르게 발전하며 ES6(ECMAScript 2015) 이후로 const
, let
, 화살표 함수(=>
), 비동기/대기(async/await
), 클래스(class
), 스프레드 문법(...
) 등 편리하고 강력한 새로운 문법과 기능들이 계속해서 추가되고 있습니다. React, Vue 등 최신 프레임워크와 라이브러리들은 이러한 최신 JavaScript 문법을 적극적으로 활용합니다.
하지만 모든 사용자의 브라우저가 최신 JavaScript 문법을 지원하는 것은 아닙니다. 특히 구형 브라우저나 일부 모바일 브라우저에서는 최신 문법을 인식하지 못하여 웹 애플리케이션이 제대로 동작하지 않는 문제가 발생할 수 있습니다. 이러한 호환성 문제를 해결하기 위해 필수적으로 사용되는 도구가 바로 Babel과 Polyfill입니다.
이번 장에서는 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.json
의browserslist
필드에 명시)에 맞춰 필요한 플러그인들을 동적으로 결정하여 적용합니다. 불필요한 변환을 줄여 번들 크기를 최적화합니다.@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.json
에 browserslist
필드 추가)
// package.json
{
...
"browserslist": [
"defaults",
"not IE 11", // IE 11 제외
"last 2 versions", // 최신 2개 브라우저 버전
"> 1%" // 점유율 1% 이상 브라우저
]
}
webpack.config.js
설정
module.rules
에 babel-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-js
와 regenerator-runtime
입니다. 최신 Babel 버전에서는 @babel/polyfill
이 deprecated 되었고 core-js
를 직접 사용하는 것을 권장합니다.
1. core-js
및 regenerator-runtime
설치
core-js
는 다양한 최신 ECMAScript 기능의 Polyfill을 제공하며, regenerator-runtime
은 async/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-env
와 useBuiltIns
옵션 활용 (권장 방식)
@babel/preset-env
의 useBuiltIns
옵션을 사용하면, 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 , JSX | Promise , fetch , Array.prototype.includes , Map |
방식 | 코드 자체를 변환하여 구형 문법으로 변경 | 누락된 기능을 구현한 코드를 런타임에 추가 |
결과 | 문법 오류 해결 | ReferenceError , TypeError 같은 런타임 오류 해결 |
함께 사용하는 이유:
대부분의 모던 웹 프로젝트는 최신 JavaScript 문법을 사용하고 새로운 API도 활용하므로, Babel과 Polyfill을 함께 사용하여 브라우저 호환성 문제를 완벽하게 해결해야 합니다. babel-loader
와 @babel/preset-env
의 useBuiltIns: "usage"
옵션이 이 둘을 효율적으로 통합하여 관리하는 가장 일반적이고 권장되는 방식입니다.
마무리하며
이번 장에서는 모든 브라우저 환경에서 안정적으로 동작하는 웹 애플리케이션을 만들기 위한 핵심 도구인 Babel과 Polyfill에 대해 학습했습니다.
여러분은 Babel이 최신 JavaScript 문법과 JSX를 구형 브라우저가 이해할 수 있는 코드로 변환하는 트랜스파일러임을 이해했습니다. 또한, Babel의 동작 원리인 플러그인과 프리셋(특히 @babel/preset-env
, @babel/preset-react
)의 역할을 파악하고, Webpack의 babel-loader
를 통해 Babel을 연동하는 방법을 배웠습니다.
이어서, Babel만으로는 해결할 수 없는 최신 JavaScript API 부족 문제를 해결하기 위한 Polyfill의 필요성을 이해하고, core-js
를 활용하여 Polyfill을 적용하는 방법을 익혔습니다. 특히, @babel/preset-env
의 useBuiltIns: "usage"
옵션을 사용하여 필요한 Polyfill만 자동으로 삽입하여 번들 크기를 최적화하는 전략을 살펴보았습니다.
Babel과 Polyfill은 개발자가 최신 JavaScript 문법의 편리함을 누리면서도, 사용자들에게 넓은 범위의 브라우저 호환성을 제공하는 데 필수적인 도구입니다. 이 장에서 배운 지식들을 바탕으로 여러분의 웹 애플리케이션이 어떤 환경에서도 안정적으로 동작할 수 있도록 최적화하시길 바랍니다.