동적인 자바스크립트 앱을 위한 ES6 사용법

How to Use ES6 for Isomorphic JavaScript Apps

원문
http://medium.com/javascript-scene/how-to-use-es6-for-isomorphic-javascript-apps-2a9c3abe5ea2



이제 먼지는 좀 가라앉았고, 나는 결국 프로덕션 앱에 ES6를 사용하기 시작했다. 그리고 isomorphic Javascript를 작업하기 때문에 Node.js와 Browser 둘 다 작동 해야한다.

이글은 ES6의 기능이나 동적인 자바스크립트에 대한 깊은 튜토리얼은 아닐것이다. 기본적인 내용으로 Babel 환경에서 개발하고 실행할 수 있게 하는데에 촛점을 두고있다.

Use Babel

Babel

Babel.js(이후 바벨)는 ES6 코드를 ES5 형태로 transpile해서 Node.js와 브라우저에서 지금 바로 사용할 수 있게 하는 좋은 툴이다. 그러나 셋팅하는 방법이 쉽진 않다.

Install Babel

바벨에 관한 튜토리얼들은 바벨을 글로벌에 설치하라고 말하는데 이는 당신의 코드가 다른 사람들과 공유되지 않을 때에만 적합하다. 만약 팀 프로젝트이거나 오픈소스 라이브러리를 개발한다면 프로젝트 패키지당 하나씩 로컬로 설치하는게 좋다.

$ npm install -g babel
$ npm install --save-dev babel

설치가 완료되면 babel-node를 실행해 REPL을 볼 수 있다.

$ babel-node
> Object.assign({}, {msg: 'wow!'}); // => { msg: 'wow!' }

브라우저 환경을 위해서는 아래와 같은 것들이 필요하다.

$ npm install --save-dev babelify browserify

이로써 당신은 arrow function과 같은 ES6의 새롭고 좋은 기능들을 사용할 수 있게 된다.

(x) => x + 1;

하지만 새로운 built-in method인 Object.assign()이나 Object.is() 같은 메소드를 사용할 수는 없다. 이게 조금 애매한데 왜냐하면 babel-node의 REPL에서는 제대로 동작하기 때문이다.

Object.is(NaN, NaN); // => true

다행히 폴리필을 이용하면 쉽게 해결된다.

npm install --save core-js

그리고 엔트리 파일 상단에 아래의 내용을 추가하면 된다.

require('core-js');

Linting

혹시 코드 린트를 포기하게 될까봐 적정한다면 걱정할 것 없다. ESLint를 이용하면 된다.

$ npm install --save-dev eslint

내가 사용하고있는 .eslintrc 파일을 보려면 클릭

envecmaFeatures 키에 해당되는 내용을 살펴보면 ESLint가 ES6 코드를 만났을때 에러가 발생하는 것을 방지할 수 있다.

리액트 코드에서 자주쓰이는 ES7의 오브젝트 rest나 spread 프로퍼티를 사용하고자 한다면 babel-eslint가 필요할 것이다.

Compiling

바벨 문서에는 컴파일링이 쉬운것 처럼 말한다.

$ babel script.js --out-file script-compiled.js

보기엔 쉬워보인다. 하지만 이렇게 하는 것은 내부에서 아무런 모듈을 임포트하지 않았을 때에나 정상적으로 동작한다. 보통은 내부에 디펜던시 관계가 있는 모든 코드 베이스 전체를 컴파일하길 원할 것이다.(한 개의 파일이 아니고) 이럴 때는 -d 옵션을 사용한다.

$ babel -d build-dir source-dir

첫번째 디렉토리가 아웃풋 디렉토리이다.

그리고 node-inspector가 정상적으로 작동하려면 소스 맵이 필요한데 -s옵션으로 소스 맵을 만들게 된다.

$ babel -d build-dir source-dir -s

이렇게 하면 필요한 모든 파일들이 컴파일이 되고 소스 맵파일을 만들어 디버거에서 라이브 코드가 실제로 어떤 원본 소스에 해당하는지 정확하게 찾을 수 있게된다. 다시 말하면 디버거에서 바벨이 생성한 컴파일된 자바스크립트코드가 아니라 컴파일되기 전애 직접 작성한 원본 코드로 디버깅을 할 수 있다.(역: *_*)

브라우저를 위한 컴파일에는 Babelify라는 Browserify 트랜스폼이 필요하다. 아래와 같이 사용하면 된다.

$ browserify script.js -t babelify --outfile bundle.js

기존 모듈의 사용

위에 언급된 툴을 이용하면 ES6이나 Node-style의 모듈을 ES6 문법을 이용해 사용할 수 있다. (역: NodeJS의 CommonJS방식과 ES6에서 제공하는 Import방식의 모듈을 특별한 작업 없이 바로 사용할 수 있다는 이야기)

import 'core-js'; // Node module
import harness from './harness'; // ES6 module

그래서 npm 생태계에서 지원 하는 엄청난 양의 표준 모듈을 특별한 작업 없이 ES6 코드 베이스로 바로 사용할 수 있게된다. 하지만 많은 사람들이 아직 ES5를 사용하고 있으니 npm에 모듈을 퍼블리시 할 때는 컴파일된 버전을 퍼블리시하는 것을 추천한다.

공개용 라이브러리를 개발할 때 나는 소스들을 source 디렉토리에서 넣어두고 컴파일된 ES5코드들은 distlib에 둔다. package.jsonmain키 값을 컴파일된 ES5 버전의 코드로 두는 것은 좋은 아이디어일 것이다.

자동화

나는 아래의 커맨드를 npm 스크립트에 등록하고 사용한다.

"scripts": {
    "lint": "eslint source",
    "clean": "rm -rf build/* && mkdir build/public && mkdir build/server && mkdir build/client",
    "build-server": "babel -d build/server source/server -s",
    "build-client": "browserify source/client/index.js -t babelify --outfile build/client/bundle.js",
    "build": "npm run clean && npm run build-server && npm build-client"
}

React

리액트에서도 잘 동작한다. Babel하고 ESLint가 JSX를 지원하기 때문이다.

Party Time

축하한다! 당신은 동적인 자바스크립트 앱을 위해 ES6를 사용할 준비가 되었다. 혹시라도 궁금해 할까봐 내가 자주 사용하는 ES6의 유용한것들의 키워드를 나열해본다.

  • Compact object literals
  • Destructuring
  • Arrow functions (한 줄 람다에 최고)
  • Default params
  • Rest params
  • Generators

당신은 새로운 Defaults/overrides 패턴을 바로 익혀두기 바란다.

ES6 Defaults / Overrides Pattern

디폴트 파라메터와 간단한 버전의 디폴트/오버라이드 패턴 구현

function foo ({
    bar = 'no',
    baz = 'works!'
} = {}) {

    return (`${bar}, ${baz}`);
}

console.log(foo({
    bar: 'yay'
})); // logs 'yay, works!'

ES5 버전에서는 Object.assign()을 대체할 약간의 폴리필이 필요하다.

var assign = Object.assign;

var defaults2 = {
    bar: 'no',
    baz: 'works!'
};

function foo2 (options) {
    var settings = assign({}, defaults2, options),

    bar = settings.bar,
    baz = settings.baz;

    return (bar + ', ' +baz);
}

console.log(foo2({
    bar: 'yay'
})); // logs 'yay, works!'