CommonJS & ES Modules

HYl·2022년 3월 7일
0

CommonJS와 ES Modules은 왜 함께 할 수 없을까 ?

자바스크립트 개발을 하다보면 require나 import 키워드를 통해 외부 라이브러리를 불러오는 코드를 자주 보게 된다.

  • require: NodeJS에서 사용되고 있는 CommonJS 키워드
  • import: ES6(ES2015)에서 새롭게 도입된 키워드
  • 두 개의 키워드 모두 하나의 파일에서 다른 파일의 코드를 불러온다는 동일한 목적을 가지고 있지만, 비슷한듯 약간씩 다른 문법 때문에 종종 우리를 혼란스럽게 한다.

노드14 에서는 옛날 스타일의 CommonJS와 (이하 CJS) 새로운 스타일의 ESM Scripts (이하 MJS) 두개가 공존하고 있다. CJS의 경우 require()와 module.exports를 사용하며, ESM은 import와 export를 사용한다.
( 정확히는 ECMAScript Modules - Experimental Warning Removal 이다. )

  • ESM에서는 require()를 사용할 수는 없다. 오로지 import만 가능하다
  • CJS도 마찬가지로 import를 사용할 수는 없다.
  • ESM에서 CJS를 import하여 사용할 수 있다. 그러나 오로지 default import만 가능하다.
  • ESM을 CJS에서 require()로 가져올 수는 있다. 그러나 이는 별로 권장되지 않는다. 그 이유는 이를 사용하기 위해서는 더 많은 boilerplate가 필요하고, 최악의 경우 Webpack이나 Rollup 같은 번들러도 필요 하다. 그 이유는, ESM가 require()에서 어떻게 동작해야 하는지 모르기 때문이다.
  • CJS는 기본값으로 지정되어 있다. 따라서 ESM 모드를 사용하기 위해서는 opt-in해야 한다. .js를 .mjs로 바꾸거나, package.json에 "type": "module" 옵션을 넣는 방법이 있다. (기존에 CJS를 쓰던 것은 .cjs로 바꾸면 된다.)

ESM과 CJS는 완전히 다르다.

CommonJS에서는 require()는 동기로 이루어진다. 따라서 promise나 콜백 호출을 리턴하지 않는다. require()는 디스크로 부터 읽어서 (네트워크 일수도 있다) 그 즉시 스크립트를 실행한다. 따라서 스스로 I/O나 부수효과 (side effect)를 실행하고 module.exports에 설정되어 있는 값을 리턴한다.

반면에 ESM은 모듈 로더를 비동기 환경에서 실행한다. 먼저 가져온 스크립트를 바로 실행하지 않고, import와 export구문을 찾아서 스크립트를 파싱한다. 파싱 단계에서, 실제로 ESM 로더는 종속성이 있는 코드를 실행하지 않고도, named imports에 있는 오타를 깜지하여 에러를 발생시킬 수 있다.

그 다음 ESM 모듈 로더는 가져온 스크립트를 비동기로 다운로드 하여 파싱한다음, import된 스크립트를 가져오고, 더 이상 import 할 것이 없어질 때까지 import를 찾은 다음 dependencies의 모듈 그래프를 만들어 낸다. 그리고, 스크립트는 실행될 준비를 마치게 되며, 그 스크립트에 의존하고 있는 스크립트들도 실행할 준비를 마치게 되고, 마침내 실행된다.

ESM 모듈 내의 모든 자식 스크립트들은 병렬로 다운로드 되지만, 실행은 순차적으로 진행된다


REFERENCE

profile
꾸준히 새로운 것을 알아가는 것을 좋아합니다.

0개의 댓글