ECMAScript Essence - Module SystemModule System
옛날 옛적에 호랑이 담배피던 시절에는 자바스크립트 코드를 담고 있는 파일을 다른 자바스크립트 파일에서 사용할 수 없었다. 어처구니 없지만 사실이다! 하는 수 없이 HTML에 도움으로 결합해서 사용해야만 했다. 이러한 치명적인 결함을 해결하기 위해서 여러 모듈시스템 기술이 등장하기 시작했다.
HTML 파일에서 .js 확장자의 파일들을 임포트하면 파일들의 코드는 하나의 파일에서 작성한 것처럼 취급된다. 이 방법에 문제점은 파일이 많아지거나 여러 개발자들이 나누어서 개발한다면 자원의 충돌이 빈번하다는 점이다. 그래서 글로벌 스코프 변수를 사용하는 것은 금기가 되었고 스코프를 완벽하게 분리할 수 있는 방법이 필요해진다.
불편함을 느낀 많은 개발자들이 앞 다투어 자바스크립트의 치명적인 약점을 개선하고자 시도했다. 이에 따라서 코드를 여러 파일로 분리해서 개발하고 조립하여 사용해도 자원의 충돌이 발생하지 않는 모듈시스템 기술들이 속속 발표되었다.
자바스크립트에게 홀로 설 수 있는 자유를 안겨 준 노드는 CommonJS 방식의 모듈시스템을 채택했다. 노드를 서버에서 사용하는 환경이라면 require 문법을 사용하는 것이 좋다.
한편 표준 단체인 ECMA는 ES6에서 import ~ from으로 대표되는 모듈시스템을 발표했다. 브라우저에서 사용하는 환경이라면 표준문법을 사용하는 것이 좋다.
문제는 클라이언트 사이드 개발인데 앵귤러, 리액트 모두 ECMA의 import ~ from 문법을 선호해서 발생한다. 왜냐하면 import ~ from 문법을 노드는 지원하지 않기 때문이다. 따라서 Babel(구 6to5)을 사용하여 트랜스파일링을 한 결과를 얻은 다음에야 노드 컴파일러를 통해서 코드를 실행할 수 있다.
대부분의 자바스크립트 IDE 툴은 노드를 자바스크립트 코드의 실행도구로 사용하므로 불편하더라도 import ~ from 문법 사용 시 require 문법으로 바꾸는 작업을 선행해야 한다. 그러한 만큼 불편함이 발생한다. 환경설정을 통해 자동으로 트랜스파일링 작업이 수행되도록 IDE 도구를 셋팅해 놓으면 번거로움을 최소화 할 수 있다.
Node Module System
모든 자원이 자동으로 외부에 제공되지는 않는다. 선택적으로 공개한 자원만이 제공된다. 외부에 제공하고 싶은 자원을 노드가 제공하는 module.exports 객체에 등록한다. module.exports 객체를 가리키는 별칭인 exports를 통해서도 등록할 수 있다.
provider.js
consumer.js
위 코드에서 ./ 기호는 같은 폴더 내에 존재한다는 뜻으로 생략하면 노드의 빌트인 모듈이나 node_modules 폴더에 설치된 써드 파티 기술을 의미하게 된다.
provider는 provider.js 파일을 가리킨다. 확장자는 생략할 수 있다.
ECMA Module System
ECMA 협회가 제정한 표준 모듈기술이다. 하지만 컴파일 작업은 노드가 수행하는데 노드는 표준 모듈 기술을 지원하지 않는다. 따라서, 표준 문법으로 작성한 코드를 노드의 문법으로 바꾼 다음에 실행해야 한다.
Transpiling 방법
트랜스파일링 작업은 다음 3가지 중에 하나를 사용한다. 편리함에서 차이가 있을 뿐 실제로 트랜스파일링을 수행하는 것은 Babel이라는 점은 변함이 없다.
콘솔을 이용하여 수행
Babel을 설치하고 개발자가 직접 콘솔에서 명령어를 사용하여 트랜스파일링 작업을 수행한다. 가장 번거로운 방식이다.
IDE 툴을 이용하여 수행
아톰에 language-babel 패키지를 설치한 후 트랜스파일링 작업을 수행시킨다.
앵귤러가 제공하는 CLI 도구를 이용하여 수행
트랜스파일링 작업뿐 아니라 번들링, 테스트 서버까지 제공하는 앵귤러의 CLI 도구를 사용하면 가장 편리하게 트랜스파일링 작업을 수행시킬 수 있다.
Transpiling 처리순서
콘솔에서 babel 명령어를 사용하여 트랜스파일링을 수행할 수 있지만 조금 불편하다. 에디터를 사용하는 경우 에디터의 플러그인을 추가하고 환경설정을 통해서 대신 수행시키는 편이 보다 편리하다.
language-babel 설치
아톰 설정에서 language-babel 패키지를 설치한다.
language-babel 환경설정
다음 그림을 참고하여 language-babel 패키지의 설정을 조절한다.
또는 프로젝트별로 .languagebabel 파일을 두고 사용할 수도 있다.
.languagebabel
.babelrc 작성
Babel Runtime Configuration 설정파일을 만든다. latest 문자열은 babel-preset-latest 트랜스파일링 라이브러리를 지칭한다.
.babelrc
package.json 파일 생성
$ npm init -y
트랜스파일링 라이브러리 설치
$ npm install --save-dev babel-preset-latest
파일을 작성하고 저장하여 트랜스파일링
provider.es6
consumer.es6
파일의 확장자를 .js로 바꾼다고 하더라도 실행할 수 없다. 왜냐하면 노드 컴파일러는 import ~ from 구문을 모르기 때문이다. 따라서 바벨을 사용하여 트랜스파일링을 수행하고 그 결과로 만들어진 .js 파일을 실행한다.
provider.es6, consumer.es6 파일에서 저장을 시도하면 트랜스파일링 작업이 이루어진다.
생성된 .js 파일을 실행
consumer.js 파일을 실행해 보자.
ECMA 모듈시스템은 사용문법이 노드의 모듈시스템보다 복잡하다. 자세한 사항은 다음 사이트를 참고하자.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import
http://2ality.com/2014/09/es6-modules-final.html
IIFE
Immediately Invoked Function Expression은 즉시 실행 함수 표현식이라고 부른다. IIFE 방식을 사용하면 스코프를 완벽히 분리하여 자원의 충돌 및 손실을 막을 수 있다. 따라서, 소스코드를 복사해서 다른 자바스크립트 파일 어느 위치에나 끼어 넣어서 사용하거나 HTML을 통한 자바스크립트 파일들 결합 시 스코프 충돌에 대한 걱정을 덜 수 있다.
실무에서는 HTML에서 다수의 자바스크립트 파일들을 모두 인클루드하기 보다는 써드파티가 제공하는 번들러를 사용하여 다수의 파일을 하나의 파일로 묶은 후 사용하는 것을 선호한다. 처리방법은 다음과 같다.
스코프를 분리하고자 하는 코드를 IIFE 표현식으로 감싼다.
글로벌 객체에 고유한 네임스페이스를 추가한다.
IIFE 함수에 네임스페이스 객체를 전달한다.
함수안에서 네임스페이스 객체에 외부에 제공할 자원을 등록한다.
IIFE 함수가 제공하는 자원은 네임스페이스 객체안에 있으므로 접근 패스를 사용하여 자원을 사용할 수 있다.
노드는 각각의 파일을 IIFE 표현식으로 감싸는 방식으로 처리하고 함수에게 module.exports 객체를 this로 전달한다. 직접 확인 해 보자.
a_provider.js
b_provider.js
consumer.js
index.html
모듈이란 객체, 함수, 기타 컴포넌트의 묶음으로써 분리된 스코프를 갖는 객체다.
댓글 없음:
댓글 쓰기