what

Babel은 JavaScript 컴파일러(Compiler)로 새롭게 등장한 JavaScript 기술을
오늘 날 모든 브라우저에서 바로 사용할 수 있도록 변환해주는 도구입니다.


  // ES5
  var o        = getDataObject(),
      products = o.products,
      memory   = o.memory,
      data     = o.data;

Why?

ES6를 사용하면 어떤 점이 좋아질까요? 비교를 해봅시다.


  // ES6
  let { products, memory, data } = getDataObject();

  // ES5
  var m = '<span>'+o.name+'</span>'+'<span class="'+o.className+'">'+o.description+'</span>';

  // ES6+
  const m = `<span>${o.name}</span><span class="${o.className}">${o.description}</span>`;

오옷! 코드가 엄청 단순해졌는걸요?

문자열 접합은 참 코드를 읽기 불편하게 만들죠... ㅠㅡㅠ

우오!! 이전보다 훨씬 사용하기 쉽군요!


  // ES5
  var hasTalkWords = words.indexOf('Talk') > -1; // true

뿐만 아니라, 코드의 역할을 보다 의미적이고 직관적으로 이해할 수 있으며


  // ES6+
  let hasTalkWords = words.includes('Talk'); // true

  // ES5
  function sum(){
    var total = 0;
    for(var i=0, l=arguments.length; i<l; i++){
      total += arguments[i];
    }
    return total;
  }

  sum(1, 20, 345, -10); // 356
  
  // ES6+
  const sum = (...args) => args.reduce((a,b) => a+b);
  
  sum(12, 4, 2, 1,2, 4, 123, 435); // 583

복잡했던 함수 로직을 단순하게 구현 할 수 있습니다.


  // ES5
  var nums = [2, 3];
  var overlap_data = [1, 30, '자유시간', true, 50, nums, '자유시간', nums];

  function hasItemInArray(item, arr){
    for (var i=0, l=arr.length; i<l; i++){
      if ( arr[i] === item ) { return true; };
    }
    return false;
  }

  function uniqueData(arr){
    var unique_data = arr.splice(0, 1);
    for ( var i=0, l=arr.length; i<l; i++ ) {
      if ( !hasItemInArray(arr[i], unique_data) ) {
        unique_data.push(arr[i]);
      }
    }
    return unique_data;
  }

  var unique_data = uniqueData(overlap_data);

  // ES 6+
  let nums = [2, 3];
  let overlap_data = [1, 30, '자유시간', true, 50, nums, '자유시간', nums];
  let unique_data = new Set(overlap_data);

새롭게 추가된 Set 데이터를 사용하면 기존의 복잡했던 일도 간결하게 처리 가능해집니다. 멋지네요!

TL; DR

모던 JavaScript 코드(ES6+) 를 모던 브라우저(IE 9+)에서 코드 호환 가능한 JavaScript 코드(ES5) 로 변환해주는 컴파일러입니다.

Browser, CLI, IDE, Build System, Frameworks 등 다양한 환경에서 활용 가능합니다.

문법 하이라이팅 지원 에디터는 다음과 같습니다.

Setup

Using Environments

Babel은 브라우저, 명령어 환경, 개발 플랫폼, 빌드 시스템, 에디터/통합개발환경 등 다양한 환경에서 활용 가능합니다.

    
    <body>

        <div id="output"></div>
    
        <!-- 독립 실행형(standalone) 버전 Babel 로드 -->
        <script src="https://unpkg.com/babel-standalone"></script>
    
        <!-- 모던 JavaScript 코드 작성 -->
        <script type="text/babel">

            const printMessage = m => m;

            document.querySelector(`#output`).textContent = printMessage(`Babel은 JavaScript 컴파일러`);

        </script>

    </body>

1. Browser Prototyping

Babel을 웹 브라우저에서 바로 실행하려면 babel-standalone 파일을 로드한 후,
text/babel 마임(MIME) 타입을 사용한 스크립트 코드 블록 내부에 모던 JavaScript 코드를 사용하면 됩니다.

하지만 이 방법은 브라우저에서 코드를 읽어 들인 후, 해석 처리해야 하기에 매우 느립니다.
즉, 권장되는 사용 방법이 아닙니다.


    # 데스크탑으로 이동
    $ cd ~/Desktop

    # Babel을 실습할 디렉토리 생성
    $ mkdir study-babel

    # 1. package.json 파일 생성
    $ echo {} > package.json

    # 2-1. npm 설치 명령을 사용하여 babel-cli 개발 모듈 로컬 설치
    $ npm install --save-dev babel-cli

    # 2-2. yarn 사용자의 경우, 아래 명령을 사용하여 설치
    $ yarn add --dev babel-cli

2. Install Babel-CLI

사용자의 로컬 컴퓨터 환경에 Babel 을 설치하여 컴파일 환경을 구성합니다.
로컬(local) 설치 방법을 사용하여 설치합니다. (
Node.js v6.x + 환경 의존)


    {
      "devDependencies": {
        "babel-cli": "^6.26.0"
      }
    }

설치가 마무리 되면 package.json 파일에 개발 의존성 정보 코드가
추가됩니다. babel-cli 개발 모듈의 설치 버전 정보를 확인할 수 있습니다.

Usage



    # 로컬 설치된 babel-cli 버전 확인
    $ node_modules/.bin/babel -V

1. Compile Files

로컬 설치된 개발 모듈을 확인하려면 node_modules/.bin/babel
쉘 명령을 통해 버전 출력 옵션 -V를 입력해봅니다.

버전이 출력되면 정상적으로 설치된 것입니다.

    
    # 기본 사용 방법
    # 모듈을 로컬 설치한 경우, babel 대신 
    # node_modules/.bin/babel로 접근하여야 
    # 명령을 실행할 수 있습니다.
    $ node_modules/.bin/babel <file.js>
    
    # 출력 파일 설정 방법
    # 옵션: -o, --out-file
    $ node_modules/.bin/babel <input.js> -o <output.js>

파일을 컴파일 하려면 babel 명령 뒤에 "파일 이름"을 넣어줍니다.
결과는 실제 파일이 생성 되지는 않고, 명령 창에 코드가 출력됩니다.

실제 파일을 생성하려면 -o 옵션을 인풋, 아웃풋 파일 이름 사이에
넣은 후 명령을 실행하면 됩니다.

Output


    # npx 명령을 사용하면 보다 쉽게 접근이 가능합니다.
    $ npm install --global npx

    # npx 설치 후에는 다음과 같이 명령을 실행할 수 있습니다.
    $ npx babel <file.js>

npx 도구를 사용하면 보다 쉽게 로컬 설치 모듈에 접근하여
사용이 가능합니다.

 

NPX


    # 워치(Watch, 변경사항 관찰) 설정
    # 옵션: -w, --watch
    $ npx babel <input.js> -o <output.js> -w

파일을 저장할 때마다 컴파일을 실행 시키려면
관찰(워치, Watch) 옵션을 추가한 후 실행합니다.

    
    # 소스맵 설정
    # 옵션: -s, --source-maps
    # 값: true 또는 false 또는 inline
    $ npx babel <input.js> -o <output.js> -s
    
    # 인라인 소스맵 설정
    $ npx babel <input.js> -o <output.js> -s inline

Watch

다수의 파일을 번들링(묶음)할 경우, 디버깅에
어려움이 있어 오류 감지를 용이하게 하기 위한
소스맵(*.map) 파일을 생성합니다.

Sourcemap

별도의 소스맵 파일 생성 없이 인라인으로
소스맵 코드를 삽입할 경우 inline 값을
설정합니다.


    # 디렉토리 설정
    # 옵션: -d, --output-dir
    $ npx babel <input_dir> -d <output_dir>

2. Compile Directories

1개 이상의 파일을 일일이 컴파일하는 것은 수고스럽습니다.
이럴 경우, 디렉토리 컴파일이 보다 효율적 입니다.

디렉토리 컴파일 시에는 -d 옵션을 사용합니다.


    # 디렉토리 파일을 한 개의 파일로 컴파일 설정
    $ npx babel <input_dir> -o <output.js> -s

디렉토리 안에 존재하는 모든 파일을 각각 컴파일 하지 않고,
하나의 파일로 묶어서 컴파일 할 경우 옵션 -o 를 사용합니다.
소스맵을 만들어 두면 디버깅이 용이하므로 -s 옵션도 사용합니다.

Directory ➔ File


    # 옵션: --ignore
    $ npx babel <input_dir> -d <output_dir> --ignore specs.js,test.js

3. ignore Files

디렉토리 내부에 컴파일 과정을 제외하고자 하는 파일들이
있다면? 옵션 --ignore 를 사용한 후, 제외할 파일들을
나열합니다. (콤마 사용)


    # babel-plugin-transform-es2015-block-scoping 플러그인 설치
    $ npm install --save-dev babel-plugin-transform-es2015-block-scoping

4. Transform Plugins

Babel을 설치하는 것만으로 ECMAScript 2015 (ES6) 코드를 ES5 코드로 변경할 수 없습니다. ES5 코드로 변경하도록 하려면 플러그인을 설치해 사용해야 합니다. transform-es2015-block-scoping 플러그인은 let, const를 사용한 블록 영역 코드를 ES5에서 호환 가능하도록 변경합니다.


  # 플러그인을 사용해 컴파일 처리
  $ npx babel <input.js> -o <output.js> --plugins transform-es2015-block-scoping

  ES2015 플러그인
  
  check-es2015-constants
  es2015-arrow-functions
  es2015-block-scoped-functions
  es2015-block-scoping
  es2015-classes
  es2015-computed-properties
  es2015-destructuring
  es2015-duplicate-keys
  es2015-for-of
  es2015-function-name
  es2015-literals
  es2015-object-super
  es2015-parameters
  es2015-shorthand-properties
  es2015-spread
  es2015-sticky-regex
  es2015-template-literals
  es2015-typeof-symbol
  es2015-unicode-regex

트랜스폼 플러그인 목록은 Transform Plugins를 참고하세요.

Babel Plugins


    # babel-presets-env 프리셋 설치
    $ npm install --save-dev babel-env

5. Preset Plugins

Babel은 상당히 많은 플러그인을 제공하고 있습니다. 사용자는 다양한 플러그인 중 원하는 플러그인 조합을 사용할 수 있지만,
일일이 플러그인을 조합하는 일은 상당히 번거롭습니다. Babel Team은 사용자의 편의를 위해 사전에 플러그인이 조합된
프리셋을 제공하고 있습니다. 이를 사용하면 플러그인을 일일이 조립할 필요가 없습니다.


  # 프리셋을 사용해 컴파일 처리
  $ npx babel <input.js> -o <output.js> --presets env

  프리셋 플러그인
  
    env
    es2015
    es2016
    es2017
    react
    flow

프리셋 플러그인 목록은 Preset Plugins를 참고하세요.

Babel Presets


  {
    "presets": ["env"]
  }

6. Configuration File

CLI 명령어를 직접 입력하여 트랜스폼 플러그인 또는 프리셋 플러그인을 설정하는 것은 매우 번거롭습니다.
명령 줄에 직접 입력하지 않더라도 설정 파일을 만들어 사용하면 일일이 플러그인을 설정할 필요가 없어 번거로움이 줍니다. (옵션 참고)


  # .babelrc 파일을 읽어들인 후, 컴파일 처리
  $ npx babel <input.js> -o <output.js>

.babelrc


  {
    "presets": [
      ["env", {
        "targets": {
          "browsers": ["last 2 versions", "ie >= 9", "> 5% in KR"]
        }
      }]
    ]
  }

브라우저 지원 범위에
맞춰 컴파일 설정하고자
할 경우 다음과 같이
설정할 수 있습니다.

설정방법을 참고하세요.


  {

    // ... 
    ,
    "babel": {
      "presets": ["env"]
    }

  }

7. Babel Configuration

별도로 .babelrc 파일을 생성하고 싶지 않다면?
package.json 파일 내부에 babel 설정을 추가하면 됩니다.

package.json


  {

    // ... 
    ,
    "scripts": {
      // -x 옵션은 --extensions 설정으로 컴파일 처리할 파일의 
      // 확장자를 사용자 임의로 설정 가능합니다. [.es6, .es, .js, .jsx]
      "dev": "babel js -o dist/bundle.js -wsx .es6"
    },

  }

8. NPM Scripts

npx babel 을 사용한 긴 명령줄을 단축한 명령어를 사용하고 싶다면?
NPM 스크립트를 등록해 사용할 수 있습니다.

package.json


  # NPM 스크립트 dev 실행
  $ npm run dev  # yarn dev

uglify-js 개발 모듈을 설치한 후, 빌드 NPM 스크립트 명령을 추가해봅니다.


  # uglify-js 개발 모듈 로컬 설치
  $ npm install --save-dev uglify-js  # yarn add --dev uglify-js

9. Build


  {

    // ... 
    ,
    "scripts": {
      "dev": "babel js -o dist/bundle.js -wsx .es6",
      // 빌드 스크립트 추가
      // -m, --mangle | 참고: https://www.npmjs.com/package/uglify-js#cli-mangle-options
      "build": "uglifyjs dist/bundle.js -o dist/build.min.js -m reserved=['$']"
    },

  }

package.json

Advanced

IE8에서도 ES6 코드를 사용할 수 있을까?

새롭게 추가된 전역 객체 Promise, Map, Set 등은 컴파일만으로 해결되지 않는 것이 존재합니다. Babel 컴파일을 통해 변환된 ES5 코드가 IE8에서 작동하지 않는 이유이죠.
하지만 Babel은 Polyfill을 통해 이 문제를 해결할 수 있는 방법을 제공합니다.


  // ES6+
  ['Gallaxy Note 8', 'iPhone X'].forEach( (item, index) => console.log(index, item) );

Compile

Babel은 ES6 코드를 ES5 코드로 변환합니다. 변환된 코드는 IE 9+ 이상 호환이 잘됩니다.


  // ES5
  ['Gallaxy Note 8', 'iPhone X'].forEach(function(item, index){
    console.log(index, item);
  });

하지만 이 코드는IE 8에서는 작동되지 않습니다. (오류 발생)


  // Polyfill: ES3 (IE8 지원)
  if ( !Array.prototype.forEach ) { 
    Array.prototype.forEach = function(fn, scope) {
      for ( var i=0, l=this.length; i<l; i++ ) {
        fn.call(scope, this[i], i, this);
      }
    };
  }

Polyfill

Polyfill은 구현 브라우저에서도 문제없이 사용될 수 있도록 모던 브라우저의 네이티브 코드에 상응하는 코드를 말합니다.


  // ES5 코드이지만, Polyfill 덕분에 더 이상 문제가 발생하지 않습니다.
  ['Gallaxy Note 8', 'iPhone X'].forEach(function(item, index){
    console.log(index, item);
  });

Polyfill 덕분에 IE 8에서 문제가 되었던 아래 코드는 정상 작동하게 됩니다.


  <!-- Babel Polyfill 코드는 사용자 코드보다 항상 먼저 호출되어야 합니다. -->
  <script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>

  <script src="./dist/build.js"></script>

Babel Polyfill

Babel Polyfill CDN 링크를 사용하여 폴리필 할 수 있습니다. 폴리필 코드는 사용자 코드보다 항상 먼저 호출되어야 합니다.


  $ npm install --save babel-polyfill  # yarn add babel-polyfill

NPM을 사용하여 로컬 설치 하여 사용할 수도 있습니다. 폴리필 이기에 --save 로 설치해야 합니다.


  // Node.js 환경에서 사용할 경우
  require('babel-polyfill');

  // ES 모듈 임포트 사용 시
  import 'babel-polyfill';

  // webpack 에서 사용할 경우,
  module.exports = {
    entry: ['babel-polyfill', './src/main.js'],
  };

Babel Polyfill 장, 단점

babel-polyfill은 core-js, regenerator runtime을 포함하는 모듈이라고 생각하면 됩니다.

core-js는 전역에 폴리필을 추가하기 전에 브라우저 체크를 통해 해당 기능이 있는지 먼저 확인합니다.
폴리필이 필요없는 모던 브라우저에서는 폴리필을 사용하지 않아 속도가 빠릅니다.

전역 객체를 직접 수정하기 때문에 Array.prototype.repeat 과 같은 ES6+ 추가된 새로운 기능을
사용하는데 문제가 될 것이 없습니다. 즉, 지원 여부와 상관없이 개발이 가능해 매우 편리합니다.

다만, 사용하지 않는 폴리필 또한 모두 포함되기에 번들된 파일 크기가 커지게 됩니다.

babel-polyfill은 core-js, regenerator runtime을 포함하는 모듈이라고 생각하면 됩니다.

core-js는 전역에 폴리필을 추가하기 전에 브라우저 체크를 통해 해당 기능이 있는지 먼저 확인합니다.
폴리필이 필요없는 모던 브라우저에서는 폴리필을 사용하지 않아 속도가 빠릅니다.

전역 객체를 직접 수정하기 때문에 Array.prototype.repeat 과 같은 ES6+ 추가된 새로운 기능을
사용하는데 문제가 될 것이 없습니다. 즉, 지원 여부와 상관없이 개발이 가능해 매우 편리합니다.


  <script src="https://unpkg.com/babel-polyfill/dist/polyfill.min.js"></script>
  <!-- addEventLister, removeEventListener 오류 발생 시, 폴리필 로드 -->
  <script src="./lib/eventListener.polyfill.min.js"></script>

  <script src="./dist/build.js"></script>

addEventListener Polyfill

IE8에서 addEventListener, removeEventListener 등 오류가 발생한다면 eventListener Polyfill을 수동으로 추가해줘야 합니다.


  $ npm install --save-dev babel-plugin-transform-es3-property-literals

  $ npm install --save-dev babel-plugin-transform-es3-member-expression-literals

ES3 Babel Plugins

IE8에서는 객체의 키 값에 예약어(try, catch 등)을 그대로 사용할 수 없기에 키 값을 쌍 따옴표로 묶어줘야 합니다.
그리고 표현식에 사용 되는 키워드는 [] 안에 따옴표를 사용해야 합니다. (예: o['keyword']() )

IE8에서 문제없이 호환되는 코드가 자동으로 처리되도록 다음 Babel 플러그인을 설치합니다.


  {
    "presets": ["env"],
    "plugins": [
        "transform-es3-property-literals",
        "transform-es3-member-expression-literals"
    ]
  }

.babelrc

플러그인 사용을 위해 .babelrc 설정 파일을 다음과 같이 수정합니다.


  ES3 플러그인
  
  es3-member-expression-literals
  es3-property-literals

ES3 트랜스폼 플러그인 목록은 ES3 Transform Plugins를 참고하세요.

Babel

By yamoo9

Babel

Babel 학습을 위한 슬라이드.

  • 1,359