Babel의 등장 배경


  • 브라우저마다 사용하는 언어가 다르다.
  • ECMAScript2015+ 이후의 Javascript 언어를 특정 브라우저 및 버전에 따라 사용할 수 없는 문제
  • 예를 들어, 크롬 79버전 기준으로 개발했으나, IE에서는 작동이 안되는 크로스브라우징이 발생한다.
  • Babel은 이러한 크로스브라우징 이슈를 해결해준다. ECMAScript2015+ 로 작성한 코드를 모든 브라우저에 호환할 수 있도록 코드를 변환해준다.


Babel의 동작원리


교육자료 : 프론트엔드 개발환경의 이해: Babel
참고자료 : Babel 공식사이트
참고자료 : Babel Plugin Handbook

기본 동작

  1. 파싱(Parsing) - 코드를 토큰별로 분해
  2. 변환(Transforming) - 파싱한 코드를 ES5로 변환한다.(플러그인 담당)
  3. 출력(Printing) - 변환된 결과물을 출력하여 작업을 완료

ECMAScript2015+ 문법을 사용한 .js파일을 생성하고 이 파일을 IE에서도 읽을 수 있도록 변환해 보는 작업을 진행해 봅시다.

install :

    > npm install --save-dev @babel/core @babel/cli


    // Babel Input: ES2015 arrow function
    [1, 2, 3].map(data => data + 1);

    // Babel Input: ES2015 const, let 스코프
    const test = 3;
    let test2 = 5;


  • 일단 path.node.name의 값들은 무엇인지 살펴보자.
    module.exports = function myBabelPlugin() {
        return {
        visitor: {
            Identifier(path) {
            const name = path.node.name;
            
            console.log("Identifier() name:", name)

            // reverse the name: JavaScript -> tpircSavaJ
            // path.node.name = name
            //    .split("")
            //    .reverse()
            //    .join("");
            },
        },
        };
    }


babel build :

  • path.node.name의 값들을 확인할 수 있습니다.

    > npx babel app.js --plugins ./myBabelPlugin.js

    Identifier() name: map
    Identifier() name: data
    Identifier() name: data
    Identifier() name: test
    Identifier() name: test2

    ...


  • 플로그인은 visitor 객체를 반환해야 합니다. 이 객체는 바벨이 파싱하여 만든 추상 구문 트리(AST)에 접근할 수 있는 메소드를 제공합니다.
  • 그 중 Identifier() 메소드의 동작을 알아보면 Identifier()에 들어온 인자 path에 접근하면 파싱된 코드들을 뒤집어서 집어 넣는 예제입니다.
  • 실제로 ./app.js의 코드들이 뒤집혀 출력되는지 확인해봅시다.
    module.exports = function myBabelPlugin() {
        return {
        visitor: {
            Identifier(path) {
            const name = path.node.name;
            // reverse the name: JavaScript -> tpircSavaJ
            path.node.name = name
                .split("")
                .reverse()
                .join("");
            },
        },
        };
    }


직접만든 babel 플로그인을 사용해서 ./app.js 변환 :

  • path.node.name : map, data, data, test, test2 들이 뒤집혀서 출력
    // npx babel [변환할.js] --plugins [적용할 plugin]
    > npx babel app.js --plugins ./myBabelPlugin.js

    // Babel Input: ES2015 arrow function, const/let 스코프
    [1, 2, 3].pam(atad => atad + 1);
    const tset = 3;
    let 2tset = 5;


VariableDeclaration를 사용하여 const, let 스코프를 var로 변환해주는 코드 작성해보기

VariableDeclaration() 메소드는 이름 그대로 변수가 어떤 스코프로 선언되었는지 참조할 수 있습니다.

AST Node VariableDeclaration shape: * kind: "var" | "let" | "const" (required)

  • declarations: Array (required)
  • declare: boolean (default: null, excluded from builder function)


app.js에서 변수선언의 종류를 console.log로 확인

    module.exports = function myBabelPlugin() {
        return {
        visitor: {
            VariableDeclaration(path) {
                console.log("VariableDeclaration() kind:", path.node.kind) // const
                
            },
        },
        };
    }


build 결과 :

const, let이 출력

    > npx babel app.js --plugins=./myBabelPlugin.js

    VariableDeclaration() kind: const
    VariableDeclaration() kind: let


const, let -> var로 변경

    module.exports = function myBabelPlugin() {
        return {
        visitor: {
            VariableDeclaration(path) {
                console.log("VariableDeclaration() kind:", path.node.kind)
                
                // const, let -> var 로 변환
                if (path.node.kind === "const" || path.node.kind === "let") {
                    path.node.kind = "var"
                }
            },
        },
        };
    }


build 결과 :

    > npx babel app.js --plugins=./myBabelPlugin.js

    // Babel Input: ES2015 arrow function, const/let 스코프
    [1, 2, 3].map(data => data + 1);
    var test = 3;
    var test2 = 5;



플러그인 사용


babel에서 제공하는 플러그인들을 사용해서 변환해보겠습니다.

@babel/plugin-transform-block-scoping

  • block scoping을 따르는 const, let을 함수 스코핑인 const, let 처럼 블록 스코핑을 따르는 예약어를 함수 스코핑을 사용하는 var로 변경해 준다.


@babel/plugin-transform-arrow-functions

  • arrow function을 일반 함수로 변경해 준다.


@babel/plugin-transform-strict-mode

  • strict 모드는 ES5(ECMA Script 5)에 추가된 키워드입니다.
  • 자바스크립트가 묵인했던 에러들의 에러 메세지를 발생시킵니다. 즉, 엄격하게 문법검사를 하겠다로 이해하면 됩니다.
  • 스크립트 시작부분에 "use strict"를 선언하면 strict 모드로 코드를 작성할 수 있습니다.

install :

    > npm install --save-dev @babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions @babel/plugin-transform-strict-mode


package.json devDependencies 에 추가된 것을 확인할 수 있습니다.

image


build 결과 :

    > npx babel app.js --plugins=@babel/plugin-transform-block-scoping --plugins=@babel/plugin-transform-arrow-functions --plugins=@babel/plugin-transform-strict-mode

    "use strict";

    // Babel Input: ES2015 arrow function, const/let 스코프
    [1, 2, 3].map(function (data) {
    return data + 1;
    });
    var test = 3;
    var test2 = 5;


babel.config.js(기본 설정파일) 사용하기


사용하려는 babel 플러그인이 많아지면 많아질수록 커맨드 명령어도 길어지기 때문에 webpack.config.js 처럼 설정파일로 분리하여 사용하는 것이 좋습니다. 이 역할을 babel.config.js가 합니다. babelbabel.config.js 파일이 있으면 자동으로 처리합니다.

    module.exports = {
        plugins: [
            "@babel/plugin-transform-block-scoping",
            "@babel/plugin-transform-arrow-functions",
            "@babel/plugin-transform-strict-mode",
        ]
    }


build 결과 :

    > npx babel app.js

    "use strict";

    // Babel Input: ES2015 arrow function, const/let 스코프
    [1, 2, 3].map(function (data) {
    return data + 1;
    });
    var test = 3;
    var test2 = 5;