Babel의 등장 배경
- 브라우저마다 사용하는 언어가 다르다.
- 
ECMAScript2015+이후의Javascript언어를 특정 브라우저 및 버전에 따라 사용할 수 없는 문제
- 예를 들어, 크롬 79버전 기준으로 개발했으나, IE에서는 작동이 안되는 크로스브라우징이 발생한다.
- 
Babel은 이러한 크로스브라우징 이슈를 해결해준다.ECMAScript2015+로 작성한 코드를 모든 브라우저에 호환할 수 있도록 코드를 변환해준다.
Babel의 동작원리
교육자료 : 프론트엔드 개발환경의 이해: Babel
참고자료 : Babel 공식사이트
참고자료 : Babel Plugin Handbook
기본 동작
- 파싱(Parsing) - 코드를 토큰별로 분해
- 변환(Transforming) - 파싱한 코드를 ES5로 변환한다.(플러그인 담당)
- 출력(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 에 추가된 것을 확인할 수 있습니다.

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가 합니다. babel은 babel.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;
