바벨이란?
바벨은 자바스크립트 컴파일러이다. 사실 자세히 보면 컴파일러보다는 트랜스파일러에 가깝다.
자바스크립트를 자바스크립트로 변환해야하는 이유가 뭘까?
ECMAScript에는 매년 새 문법과 새 API가 추가되는데, 브라우저마다 그걸 구현한 시점과 범위가 다르다.
크롬은 지원하는 문법을 사파리는 아직 지원하지 않을 수 있고, 업데이트가 멈춘 IE11 같은 브라우저는 아예 영원히 지원하지 않는다.
지원하지 않는 문법은 실행 이전에 파싱 단계에서 SyntaxError로 죽어버린다.
그래서 새 문법으로 작성하고, 오래된 브라우저에서도 돌아가는 예전 문법으로 바꿔서 내보낸다. 이게 바벨이 하는 일이다.
여기서 구분해야 할 게 있다.
- 문법(syntax) — 화살표 함수, 클래스, 옵셔널 체이닝처럼 파서가 이해해야 하는 것. 바벨이 예전 문법으로 바꿔준다.
- API(built-ins) —
Promise,Array.prototype.includes처럼 런타임에 존재해야 하는 것. 문법 변환으로는 만들어낼 수 없어서core-js같은 폴리필로 채워 넣어야 한다.
뒤에서 볼 @babel/preset-env의 useBuiltIns, corejs 옵션이 바로 두 번째를 다루는 설정이다.
참고로 엔진이 자바스크립트를 기계어로 바꾸는 과정(JIT 컴파일)은 엔진 내부의 최적화 구현이고, 크로스 브라우징 이슈와는 관계가 없다. 문제가 되는 건 어디까지나 어떤 문법과 API를 지원하느냐다.
컴파일러
컴파일러란 소스코드를 입력받아 그것을 다른 프로그래밍 언어로 옮기는 것을 말한다. 예를들어 자바스크립트로 작성한 고급 프로그래밍 언어를 컴퓨터가 이해할 수 있는 어셈블리어로 변환하는 것이다.
트랜스파일러
트랜스파일러란 소스코드를 입력받아 그것을 같은 프로그래밍 언어(유사한 언어)의 다른 버전으로 옮기는 것을 말한다.
바벨의 동작
바벨은 ECMAScript2015+ 버전의 코드를 하위 버전의 코드로 변환한다. 이렇게 변환된 코드는 IE11을 포함한 구형 브라우저에서도 동작한다.
바벨은 세 단계로 빌드를 진행한다.
- 파싱(Parsing) : 코드를 읽어서 추상 구문 트리 AST(Abstract Syntax Tree)로 변환한다.
- 변환(Transformation) : AST를 원하는 형태로 변환한다.
- 출력(Printing) : 변환된 AST를 코드로 출력한다.
먼저 바벨을 설치한다
npm install -D @babel/core @babel/cli
const alert = msg => window.alert(msg);
위 코드를 바벨로 변환하면 아무런 변화가 없다.
npx babel app.js
const alert = msg => window.alert(msg);
바벨 플러그인
@babel/plugin-transform-block-scoping 플러그인을 사용해보자.
npm install -D @babel/plugin-transform-block-scoping
먼저 root 디렉토리에 babel.config.js 파일을 생성하고
// babel.config.js
module.exports = {
plugins: [
'@babel/plugin-transform-block-scoping'
]
}
const alert = msg => window.alert(msg);
위 코드를 바벨로 변환하면 아래와 같이 변환된다.
var alert = msg => window.alert(msg);
위 플러그인은 const, let 키워드를 var 키워드로 변환한다.
arrow function과 strict mode를 사용해보자.
npm install -D @babel/plugin-transform-arrow-functions @babel/plugin-transform-strict-mode
위 코드를 바벨로 변환하면 아래와 같이 변환된다.
"use strict";
var alert = function alert(msg) {
return window.alert(msg);
};
바벨 프리셋
바벨 프리셋은 바벨 플러그인을 모아놓은 것이다.
위 세가지 플러그인은 아래 프리셋에 모두 포함되어 있다.
npm install -D @babel/preset-env
// babel.config.js
module.exports = {
presets: [
'@babel/preset-env'
]
}
const alert = msg => window.alert(msg);
위 코드를 바벨로 변환하면 아래와 같이 변환된다.
"use strict";
var alert = function alert(msg) {
return window.alert(msg);
};
추가로 각 프리셋들은 옵션들을 제공하는데
// babel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
chrome: '79',
ie: '11'
},
useBuiltIns: 'usage',
corejs: {
version: 2
}
}
]
]
}
위처럼 지원하는 브라우저의 버전을 설정하거나, 폴리필을 사용할지 설정할 수 있다.
웹팩과 통합
바벨은 직접 사용하진 않고 웹팩과 같은 모듈 번들러와 통합해서 사용한다.
npm install -D babel-loader
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
}
js 확장자로 끝나는 모든 파일에 babel-loader를 적용한다. 또 node_modules 디렉토리는 제외한다.