바벨(Babel)
0. 들어가면서
웹팩(Webpack)에 대해 정리한 글에서 이야기한 것처럼 요즘 스프링뿐만 아니라 프론트엔드 기술에도 관심이 많아졌다. 한 가지만 잘해서 좋은 개발자가 될 수 없다는 생각도 들기 시작했다. 프론트엔드에 관련된 글을 하나 더 작성했다. 프론트엔드와 관련된 두 번째 주제는 바벨(Babel)이다.
1. Babel
Babel is a JavaScript compiler
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
공식 홈페이지에서 바벨(Babel)은 자바스크립트(JavaScript) 컴파일러(compiler)이며, ECMAScript 2015+ 코드를 현재 그리고 이전 브라우저 환경에서 호환되는 자바스크립트로 변환하는 도구라고 소개하고 있다. 바벨에 대해 알아보기 전에 ECMAScript에 대한 이해가 필요해 보인다. ES(ECMAScript)는 위키피디아(wikipedia)에 다음과 같이 정의되어 있다.
ECMAScript (/ˈɛkməskrɪpt/) (or ES) is a general-purpose programming language, standardised by Ecma International according to the document ECMA-262. It is a JavaScript standard meant to ensure the interoperability of web pages across different web browsers.
브라우저(browser)는 자바스크립트가 동작할 수 있는 런타임(Runtime)이다. 다양한 브라우저들은 내부에서 제공하는 함수나 자바스크립트 문법이 제각기 다르다. ECMAScript는 이런 다양한 브라우저 환경에서도 웹 페이지의 상호 운용성을 보장하기 위한 표준이다. 현재 ECMAScript 2021 버전까지 나온 것으로 확인된다.
많은 곳에서 바벨은 트랜스파일러(transpiler)라 표현하기도 하는데 트랜스파일러와 컴파일러(compiler)가 무엇이 다른지 알아보자. 컴파일러는 다음과 같이 정의할 수 있다.
한 언어로 작성된 소스 코드를 다른 언어로 변환하는 작업
예를 들어, 자바(Java)로 작성된 코드를 바이트 코드로 변환하는 작업이나 C/C++로 작성된 코드를 기계어로 변환하는 작업을 의미한다. 고수준의 프로그래밍 언어를 저수준의 프로그래밍 언어로 변환하는 전통적인 컴파일러를 의미한다.
트랜스파일러는 다음과 같이 정의할 수 있다.
한 언어로 작성된 소스 코드를 비슷한 수준의 추상화(abstract)를 가진 언어로 변환하는 작업
예를 들어, ES5 문법의 자바스크립트 코드를 ES6 문법의 자바스크립트 코드로 변경하는 작업이나 타입스크립트(TypeScript) 언어를 자바스크립트 언어로 변경하는 작업을 의미한다. 트랜스파일러를 source-to-source compiler라고 표현하기도 하며, 일종의 컴파일러 종류로 분류되므로 바벨을 컴파일러라고 표현해도 무방하다.
2. Background of babel - Cross Browsing
위에서 설명한 내용을 다시 간단히 정리해보면 다음과 같이 표현할 수 있다.
바벨(Babel)은 다양한 브라우저 환경에서 동작할 수 있는 자바스트립트 코드로 변환해주는 트랜스파일러
이제 바벨이 등장한 배경에 대해 정리해보자. 바벨이 등장하게 된 원인 중 하나는 크로스 브라우징(Cross Browsing) 때문이다.
크로스 브라우징이란 적어도 표준 웹 기술을 채용하여 다른 기종 혹은 플랫폼에 따라 달리 구현되는 기술을 비슷하게 만듦과 동시에 어느 한쪽에 최적화되어 치우지지 않도록 공통 요소를 사용하여 웹 페이지를 제작하는 기법을 말하는 것이다. 또한, 지원할 수 없는 다른 웹 브라우저를 위한 장치를 구현하여 모든 웹 브라우저 사용자가 방문했을 때 정보로서의 소외감을 느끼지 않도록 하는 방법론적 가이드를 의미하는 것이다.
바벨은 많은 브라우저들 중 어느 한쪽에 치우치지 않고 공통적으로 잘 동작하도록 제작하려는 크로스 브라우징 기법을 지원하는 도구이다. 바벨은 주로 최신 자바스크립트 문법을 따라가지 못하는 브라우저를 위해 ES6 이상의 최신 문법으로 작성된 코드를 ES5 문법으로 변경하는 일을 수행한다. 타입스크립트, JSX 같은 다른 언어로 작성된 코드도 변경이 가능하다.
3. How does babel work?
세 개의 단계를 통해 코드를 변환한다.
- Parse
- Babylon 파서(parser)를 사용한다.
- JavaScript 코드 문자열을 컴퓨터 친화적인 표현인 추상 구문 트리(AST, Abstract Syntax Tree)로 변환한다.
- Transform
- babel-traverse 모듈을 통해 AST를 분석하고 수정한다.
- Generate
- babel-generator 모듈을 사용하여 AST를 일반 코드로 변환한다.
추상 구문 트리(AST, Abstract Syntax Tree)는 프로그래밍 언어로 작성된 코드를 각 의미별로 분리하여 컴퓨터가 이해할 수 있는 구조로 변경시킨 트리를 의미한다. 컴파일러에 자주 사용되는 자료구조이다. 트리의 각 노드는 소스 코드로 구성된다.
이 사이트에서 코드를 사용한 추상 구문 트리를 만들어 볼 수 있다. 아래는 추상 구문 트리로 변경할 매우 간단한 기능의 자바스크립트 코드다.
function addFive(num) {
return num + 5;
}
위 코드를 변경하면 아래와 같다.
{
"type": "Program",
"start": 0,
"end": 43,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 43,
"id": {
"type": "Identifier",
"start": 9,
"end": 16,
"name": "addFive"
},
"expression": false,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start": 17,
"end": 20,
"name": "num"
}
],
"body": {
"type": "BlockStatement",
"start": 22,
"end": 43,
"body": [
{
"type": "ReturnStatement",
"start": 26,
"end": 41,
"argument": {
"type": "BinaryExpression",
"start": 33,
"end": 40,
"left": {
"type": "Identifier",
"start": 33,
"end": 36,
"name": "num"
},
"operator": "+",
"right": {
"type": "Literal",
"start": 39,
"end": 40,
"value": 5,
"raw": "5"
}
}
}
]
}
}
],
"sourceType": "module"
}
4. Examples
간단하게 바벨을 이용해 코드를 변환시켜보자. 먼저 프로젝트를 생성한다.
$ npm init -y
Wrote to D:\workspace\blog\blog-in-action\2021-10-30-babel\package.json:
{
"name": "2021-10-30-babel",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
before.js 파일을 생성 후 아래와 같은 코드를 작성한다.
[1, 2, 3].map((n) => console.log(n + 1));
다음 바벨을 설치해보자. @babel/core, @babel/cli 패키지를 설치한다.
$ npm i -D @babel/core @babel/cli
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"ia32"})
npm WARN 2021-10-30-babel@1.0.0 No description
npm WARN 2021-10-30-babel@1.0.0 No repository field.
+ @babel/core@7.16.0
+ @babel/cli@7.16.0
added 83 packages from 78 contributors and audited 84 packages in 5.831s
5 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
플러그인(plugin)과 프리셋(preset)을 통해 바벨에게 문법 변환 규칙을 알려줄 수 있다. 플러그인을 각 변환 규칙을 의미한다. 프리셋은 목적에 따라 사용할 플러그인들을 묶어 놓은 세트(set)를 의미한다. 여러 개의 플러그인을 통해 변환 규칙을 하나씩 적용할 수도 있지만, 이번 예제에선 프리셋으로 변환 규칙을 적용시켜보자. 아래 명령어로 프리셋을 설치한다.
$ npm i -D @babel/preset-env
npm WARN 2021-10-30-babel@1.0.0 No description
npm WARN 2021-10-30-babel@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.3.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"ia32"})
+ @babel/preset-env@7.16.0
added 110 packages from 21 contributors and audited 194 packages in 11.439s
12 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
이제 코드를 변환해보자. --presets 옵션을 추가하여 변환 규칙을 적용한다. 변환된 코드가 출력된다. 애로우 함수(arrow function)가 일반 함수로 변환된 것을 확인할 수 있다.
$ npx babel before.js --presets=@babel/env
"use strict";
[1, 2, 3].map(function (n) {
return console.log(n + 1);
});
변환 파일은 파일로 만들 수 있다. -o 옵션을 사용하면 변환된 코드이 파일로 저장된다.
after.js파일에 결과를 저장한다.
$ ls
before.js node_modules/ package-lock.json package.json
$ npx babel before.js -o after.js --presets=@babel/env
$ ls
after.js before.js node_modules/ package-lock.json package.json
생성된 after.js 파일 내용은 다음과 같다.
"use strict";
[1, 2, 3].map(function (n) {
return console.log(n + 1);
});
TEST CODE REPOSITORY
REFERENCE
- https://babeljs.io/docs/en/
- https://en.wikipedia.org/wiki/ECMAScript
- https://d2.naver.com/helloworld/4268738
- https://code-giraffe.tistory.com/44
- https://ideveloper2.tistory.com/166
- https://devowen.com/293
- https://hbsowo58.tistory.com/407
- https://www.daleseo.com/js-babel/
- https://tecoble.techcourse.co.kr/post/2021-07-07-babel/
- https://medium.com/@su_bak/javascript-ast-abstract-syntax-tree-606554e29898
댓글남기기