[인프런] 프론트엔드 개발환경의 이해와 실습 (바벨의 기본 개념)
바벨의 기본 개념을 알아보고, 프로젝트에 직접 적용해보자.
바벨의 기본 개념
바벨이 나온 이유
브라우저마다 사용하는 언어가 달라서 프론트엔드 코드가 일관적이지 않을 때가 많다. 인터넷 익스플로러에서 Promise를 이해하지 못하는 것 처럼 말이다. 이와 같은 크로스브라우징을 해결해 줄 수 있는 것이 바로 바벨이다. ECMAScript2015+로 작성한 코드를 모든 브라우저에서 동작하도록 호환성을 지켜준다.
바벨의 기본 동작
바벨은 EMS2015 이상의 코드를 적당한 하위 버전으로 바꿔준다. 바뀐 코드는 최신 자바스크립트 코드를 이해하지 못하는 구 버전 브라우저에서도 잘 동작한다.
바벨을 이용해 아래 코드를 바꿔보자.
src/app.js
const alert = msg => window.alert(msg)
먼저 바벨 최신 버전과 터미널 도구를 사용하기 위한 커맨드라인 도구를 설치해준다.
$ npm install -D @babel/core @babel/cli
설치 후, 바벨 명령어로 적용시킨다.
$ npx babel ./src/app.js
적용시킨 결과를 보면 빌드 이전과 달라진 게 없을 것이다. 이유는 바벨의 빌드 단계에 나타난다.
바벨은 세 단계로 빌드를 진행한다.
- 파싱: 코드를 받아서 하나하나 각 토큰으로 분리함 ex) const / alert / = / ...
- 변환: ES6 코드를 ES5로 변환 → 플러그인의 역할
- 출력: 변환된 결과를 출력
플러그인
기본적으로 바벨은 코드를 받아서 코드를 반환한다. 즉, 파싱과 출력만 담당하고 변환 작업은 플러그인이 한다.
플러그인을 직접 만들어 동작 원리를 살펴보자.
my-babel-plugin.js
module.exports = function myplugin() {
return {
visitor: {
Identifier(path) {
const name = path.node.name // 파싱된 결과물에 접근
// 바벨이 만든 AST 노드를 출력
console.log("Identifier() name:", name)
// 변환작업: 코드 문자열을 역순으로 변환
path.node.name = name.split("").reverse().join("")
},
},
}
}
플러그인 형식은 visitor 객체를 가진 함수를 반환해야 한다. 이 객체는 바벨이 파싱해서 만든 추상 구문 트리(AST)에 접근할 수 있는 메소드를 제공한다. 그 중에 Identifier() 메소드의 동작 원리를 살펴보는 코드이다.
이렇게 작성한 플러그인을 사용하기 위해서는 다음과 같이 작성하면 된다.
$ npx babel ./src/app.js --plugins ./my-babel-plugin.js
- block-scoping 플러그인은 const, let 처럼 블록 스코핑을 따르는 예약어를 함수 스코핑을 사용하는 var로 바꿔주는 역할을 한다.
- 화살표 함수를 지원하지 않는 브라우저도 있기 때문에 arrow-functions 플러그인을 이용해서 일반 함수로 바꿔줄 수 있다.
- ES5에서부터 지원하는 엄격 모드를 사용하는 것이 안전하기 때문에 "use strict" 구문을 추가하고자 strict-mode 플러그인을 사용할 수 있다.
위의 3가지 플러그인들을 설치해보자.
$ npm install -D @babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions @babel/plugin-transform-strict-mode
설치한 플러그인을 커맨드라인에서 사용하기에는 명령어가 너무 길어지기 때문에 웹팩처럼 기본 설정파일을 분리해준다.
babel.config.js
module.exports = {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-strict-mode",
],
}
이렇게 설정파일을 작성하면 아래와 같이 보다 간단한 명령어로 빌드할 수 있다.
$ npx babel ./src/app.js
프리셋
코드 한 줄을 작성하는데도 세 개의 플러그인을 세팅해야하는 상황이 발생했다. 필요한 플러그인을 일일이 설정하기 보다는 목적에 맞게 여러가지 플러그인을 세트로 모아두는 것이 좋겠다. 이게 바로 프리셋이다.
사용한 세 개의 플러그인을 하나의 프리셋으로 만들어 보자.
my-babel-preset.js
module.exports = function myBabelPreset() {
return {
plugins: [
"@babel/plugin-transform-block-scoping",
"@babel/plugin-transform-arrow-functions",
"@babel/plugin-transform-strict-mode",
]
}
}
plugins 배열에 사용한 세 개의 플러그인을 담았다.
프리셋을 사용하기 위해 바벨 기본 설정도 수정해준다.
babel.config.js
module.exports = {
presets: ["./my-babel-preset.js"],
}
플러그인 세팅 코드를 제거하고 presets 배열에 방금 만든 my-babel-preset.js를 추가했다. 실행해보면 같은 결과를 출력할 것이다.