Babel

5 분 소요


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+ 코드를 현재 그리고 이전 브라우저나 환경에서 호환되는 JavaScript로 변환하는 도구라고 소개되고 있습니다. 바벨에 대해 알아보기 전에 ECMAScript에 대한 이해가 필요해 보입니다.

1.1. ES(ECMAScript)

Wiki
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)는 JavaScript 언어가 동작할 수 있는 런타임(Runtime)입니다. 다양한 브라우저들은 내부에서 제공하는 함수나 JavaScript 문법이 제각기 다릅니다. ECMAScript는 이런 다양한 브라우저 환경에서도 웹 페이지의 상호 운용성을 보장하기 위한 표준입니다. 현재 ECMAScript 2021 버전까지 나온 것으로 확인됩니다.

ECMAScript Version

이미지 출처, https://en.wikipedia.org/wiki/ECMAScript#Versions

1.2. 바벨은 트랜스파일러(Transpiler)인가 컴파일러(Compiler)인가?

많은 곳에서 바벨은 트랜스파일러(transpiler)라 표현하기도 하는데 트랜스파일러와 컴파일러가 무엇이 다른지 알아보았습니다.

1.2.1. 컴파일러(Compiler)

한 언어로 작성된 소스 코드를 다른 언어로 변환하는 작업

예를 들어, Java로 작성된 코드를 바이트 코드로 변환하는 작업이나 C/C++로 작성된 코드를 기계어로 변환하는 작업을 의미합니다. 고수준의 프로그래밍 언어를 저수준의 프로그래밍 언어로 변환하는 전통적인 컴파일러를 의미합니다.

1.2.2. 트랜스파일러(Transpiler)

한 언어로 작성된 소스 코드를 비슷한 수준의 추상화(abstract)를 가진 언어로 변환하는 작업

예를 들어, ES5 문법의 JavaScript 소스 코드를 ES6 문법의 JavaScript 코드로 변경하는 작업이나 TypeScript 언어를 JavaScript 언어로 변경하는 작업을 의미합니다. 트랜스파일러를 source-to-source compiler라고 표현하기도 하며, 일종의 컴파일러 종류로 분류되므로 바벨을 컴파일러라고 표현해도 무방합니다.

2. Babel 등장 배경 - 크로스 브라우징(Cross Browsing)

위에서 설명한 내용을 다시 간단히 정리해보면 다음과 같이 표현할 수 있습니다.

바벨(Babel)은 다양한 브라우저 환경에서 동작할 수 있는 JavaScript 코드로 변환해주는 트랜스파일러(transpiler)

이제 바벨이 등장한 배경에 대해 정리해보겠습니다. 바벨이 등장하게 된 원인 중 하나는 크로스 브라우징(Cross Browsing) 때문입니다.

Cross Browsing
Cross Browsing이란 적어도 표준 웹 기술을 채용하여 다른 기종 혹은 플랫폼에 따라 달리 구현되는 기술을 비슷하게 만듦과 동시에 어느 한쪽에 최적화되어 치우지지 않도록 공통 요소를 사용하여 웹 페이지를 제작하는 기법을 말하는 것이다. 또한, 지원할 수 없는 다른 웹 브라우저를 위한 장치를 구현하여 모든 웹 브라우저 사용자가 방문했을 때 정보로서의 소외감을 느끼지 않도록 하는 방법론적 가이드를 의미하는 것이다.

바벨은 많은 브라우저들 중 어느 한쪽에 치우치지 않고 공통적으로 잘 동작하도록 제작하려는 크로스 브라우징 기법을 지원하는 도구입니다. 바벨은 주로 최신 JavaScript 문법을 따라가지 못하는 브라우저를 위해 ES6 이상의 최신 문법으로 작성된 코드를 ES5 문법으로 변경하는 일을 수행합니다. TypeScript, JSX 같은 다른 언어로 작성된 코드도 변경이 가능합니다.

3. Babel 동작

세 개의 단계를 통해 코드를 변환합니다.

  1. Parse
    • Babylon 파서(parser)를 사용합니다.
    • JavaScript 코드 문자열을 컴퓨터 친화적인 표현인 추상 구문 트리(AST, Abstract Syntax Tree)로 변환합니다.
  2. Transform
    • babel-traverse 모듈을 통해 AST를 분석하고 수정합니다.
  3. Generate
    • babel-generator 모듈을 사용하여 AST를 일반 코드로 변환합니다.

이미지 출처, https://www.sitepoint.com/understanding-asts-building-babel-plugin/

3.1. 추상 구문 트리(AST, Abstract Syntax Tree)란?

다소 생소할 수 있는 용어인 추상 구문 트리(AST, Abstract Syntax Tree)에 대해 간단한 정리를 하였습니다.

  • 프로그래밍 언어로 작성된 코드를 각 의미별로 분리하여 컴퓨터가 이해할 수 있는 구조로 변경시킨 트리를 의미합니다.
  • 컴파일러에 자주 사용되는 자료구조입니다.
  • 트리의 각 노드는 소스 코드로 구성됩니다.
  • https://astexplorer.net/ 사이트에서 코드를 사용한 추상 구문 트리를 만들 수 있습니다.
JavaScript 코드
  • 추상 구문 트리로 변경할 매우 간단한 기능의 JavaScript 코드입니다.
function addFive(num) {
    return num + 5;
}
추상 구문 트리
  • 위의 간단한 JavaScript 코드를 변경하면 아래와 같습니다.
{
  "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. Babel 사용 예제

간단하게 바벨을 이용해 코드를 변환시켜보겠습니다.

4.1. npm 프로젝트 만들기

  • npm 프로젝트를 만듭니다.
$ 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"
}

4.2. 테스트 JavaScript 코드

  • 파일명을 before.js로 만듭니다.
  • 내부 코드는 아래와 같이 작성합니다.
[1, 2, 3].map((n) => console.log(n + 1));

4.3. Babel 설치

  • @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

4.4. 플러그인(plugin), 프리셋(preset) 설정

  • 플러그인과 프리셋을 통해 Babel에게 문법 변환 규칙을 알려줄 수 있습니다.
  • 플러그인을 적용하여 변환 규칙을 하나씩 미세하게 적용할 수 있습니다.
  • 프리셋은 목적에 따라 사용할 플러그인들을 묶어 놓은 세트(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

4.5. 변환하기

  • --presets 옵션을 추가하여 변환 규칙을 적용합니다.
  • 변환된 코드가 아래 출력됩니다.
  • 애로우 함수(arrow function)가 일반 함수로 변환된 것을 확인할 수 있습니다.
$ npx babel before.js --presets=@babel/env
"use strict";

[1, 2, 3].map(function (n) {
  return console.log(n + 1);
});

4.6. 변환 파일 만들기

  • -o 옵션을 사용해 변환된 코드를 파일로 저장할 수 있습니다.
$ 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

카테고리:

업데이트: