Babel이란?
- 구형 브라우저나 환경에서 ES6+ 문법을 사용하기 위해 이전 버전의 자바스크립트 문법으로 변환해주는 도구
ES6 기준 (2015.06 출시)
- 브라우저들은 ES6를 지원하기 위해서 약 1년에서 2년정도의 기간이 걸렸습니다.
- 그렇다면 웹 개발자들은 이 기간동안 ES6 문법들을 사용하지 못했을까요?
- 그렇지 않습니다! => Babel을 통해 ES6+를 이전 문법으로 다운그레드 해줘서 사용해줬습니다.
Babel 사용법
간단한 예시: 화살표 함수 transpiling
const fn = () => "바벨은 대단해"
- 다음 코드를 transpiling 하기 위해서는 3가지 도구가 필요합니다.
- @babel/core: 바벨의 핵심적인 기능
- @babel/cli: 터미널로 바벨을 사용
- @babel/plugin-transform-arrow-functions: 화살표 함수를 transform하는 플러그인
./node_modules/.bin/babel [변경할 파일] --out-dir [변환될 위치] --plugins=@babel/plugin-transform-arrow-functions
- 이런식으로 명령어를 입력하게되면 아래와 같은 형식으로 transform됩니다.
var fn = function fn(){
return "바벨은 대단해"
}
- 하지만 ES6+에는 많은 기능들이 추가되었는 데 이러한 기능을 transform할 때마다 이런 플러그인들을 하나하나 설치해야할까요? 또 매번 복잡한 명령어를 입력해야 할까요?
- 아니요? 보통은 babel.config.json이라는 설정 파일과 Preset을 활용합니다.
- 설정 파일에는 config와 rc 파일이 있습니다.
babel.config.json
{
"presets": [
"@babel/preset-env",
{
"targets":{
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
]
}
- preset은 다양한 플러그인을 모아놓은 집합 같은 개념
- preset을 활용하여 별도의 플러그인을 설치하지 않고 transpiling 진행 가능
Polyfill
- Polyfill은 충전솜이라는 뜻을 가지고 있는데요.
- 구형 브라우저에서 지원하지 않는 최신 기능을 지원하고자 가져오는 코드 뭉치
- Babel은 Preset과 Plugin을 통해서 트랜스파일링을 진행합니다.
- 트랜스파일링을 진행해도 모든 코드가 다 변하는 것이 아니라 Promise와 Array.prototype.incolues 같은 인스턴스 메서드들은 트랜스파일링이 진행되어도 그대로 남아있습니다.
- 이럴때 필요한 게 Polyfill입니다. Polyfill은 런타임 환경에서 위와 같은 코드가 존재하지 않는다면 해당 코드를 추가해줍니다. => 부족한 부분을 채워주는 솜뭉치!
- 예전에는 @babel/polyfill을 사용했으나 Babel 7.4.0부터는 deprecated
- 현재는 core-js라는 것이 @babel/polyfill을 대체하고 있습니다.
useBuiltIns: entry
"useBuiltIns": "entry",
"corejs": "3.22"
import "core-js"
import "core-js/modules/es.set"
- useBuiltIns옵션과 corejs 버전 명시를 같이하게 되면 import할 때 효과를 볼 수 있습니다.
- useBuiltIns: entry => core-js/stable과 regenerator-runtime/runtime 모듈을 전역 스코프에 직접 삽입한 경우 이를 타깃 환경에 필요한 폴리필만 전역 스크포에 추가되도록 변경
useBuiltIns: usage (사용하는 것을 권장)
- 실제 필요한 폴리필만 삽입
- import 자체를 삽입해줘서 따로 삽입할 필요 없음
var a = new Set();
import "core-js/modules/es.set";
var a = new Set();
core-js 단독 사용
- 전역 스코프가 오염될 수 있다는 단점을 가지고 있습니다.
- 전역 스코프가 오염되었을 때 라이브러리를 사용할 때 예상치 못한 에러가 발생한다거나 이름 충돌이 발생할 수 있습니다.
{
"presets": [[
"@babel/preset-env"
]],
"plugins":[
["@babel/plugin-transform-runtime", {
"core-js": 3
}]
]
}
- 이런식으로 플러그인을 설치하고 core-js 버전 명을 명시하게되면 core-js-pure 패키지에서 폴리필 삽입
- 만약에 프로젝트 내 패키지 중 전역 스코프에 의존하는 패키지가 존재한다면?
- 해당 패키지를 포함해서 트랜스파일링을 진행해야합니다. (axios는 전역 Promise에 의존한다고 하네요)
babel.config.json / babelrc.json
babel.config.json
- 여러 패키지 디렉토리를 가진 프로젝트에서 하나의 바벨 설정을 적용하고 싶을 때
- node_modules도 적용하고 싶을 때 (axios에서 일어난 문제 해결!)
babelrc.json
- 프로젝트 내에 서드 파티 라이브러리가 바벨에 의해 트랜스폼되기를 바라지 않는 경우
Webpack과 함께하는 Babel-loader
- 어느정도 규모가 있는 프로젝트의 경우 보통 Webpack같은 모듈 번들러를 사용합니다.
- 각 파일의 의존성을 파악해서 몇 개의 압축 파일로 만들어주고 최적의 결과를 만들어줍니다.
- 이러한 Webpack과 Babel을 연결시켜주는 것이 Babel-laoder입니다.
module.exports = {
module: {
rules: [
{
test: /\.m?js$/i,
exclude: /node_modules/,
use: {
lodaer: 'babel-loader',
options: {
presets: ["@babel/preset/env"]
}
}
}
]
}
}
babel-loader vs ts-loader
const str: string = 9;
-
babel-loader: 에러 X
-
ts-loader: 에러 O
-
bebel-loader는 타입 체크를 하지 않는다.
-
enums 지원 x
- 하지만 2021.7.26에 출시한 Babel 7.15버전부터는 모든 TS 코드 베이스를 컴파일 할 수 있다고 합니다.
-
Babel은 ECMAscript spec 기준이다보니 Decorator 같은 TypeScript에서 변화가 많은 기능은 지원하지 못합니다.
- 하지만 관련 플러그인을 사용하면 이 도한 가능합니다.
-
babel-lodaer와 ts-lodaer의 속도를 비교해보면 프로덕트 환경과 개발 환경 둘다 babel-lodaer가 더 빨랐습니다.
마무리
이번 글에서는 babel에 관한 내용을 다뤘는데요. babel은 ES6+ 문법을 이전 문법으로 변환해주는 라이브러리라고만 알고 있었는 데 더 자세한 내용을 알게되어서 좋았습니다. 특히 Polyfill에 대한 개념과 babel-loader와 ts-lodaer를 비교하는 부분이 굉장히 흥미로웠습니다. 해당 영상의 내용대로라면 webpack을 구성할 때 관련 플러그인만 잘 설치한다면 ts-lodaer는 필요 없다는 것으로 이해했는데요. 최근에는 Vite를 통해서 간단하게 프로젝트를 생성하고 webpack을 통해 하나하나 프로젝트를 구성해본적은 오래된 거 같습니다. 조만간 webpack을 이용해서 프로젝트를 구성해봐야겠네요.
Reference