본문 바로가기

자바스크립트의 정석 🟡

[자바스크립트] CommonJS vs ES Modules

참고자료1

참고자료 2

 

 

 

📕 JS 모듈을 내보내는 방식은 두가지가 있다.

- 📌 모듈이란? 여러 기능들에 관한 코드가 모여있는 하나의 파일 

- 첫번째는 module.exports로 모듈을 내보내고 require()로 접근하는 CJS(CommonJS)

- 두번째는 export로 모듈을 내보내고 import로 접근하는 ESM(ES Modules)가 있다.

 

//CJS
modules.exports = { ... }  //모듈 내보낼때
const utils = requires('utils');  //모듈 가져올 때
// ESM 방법
export.default = () => {... }; //모듈을 내보낼 때
import utils from 'utils'; // 모듈 가져올 때

 

 

✨차이점

1. CJS 방식

- require로 모듈을 접근하고 module.exports로 모듈을 내보내는 ESM 방식

- Node.js에서 지원하는 모듈 방식으로 초기 Node 버전부터 사용

- 별도의 설정이 없다면 CJS가 기본값

 

1) 모듈에 접근할 때 require()

- 외부 모듈에 접근할때는 require()을 사용

 

2) 내보낼 때는 module.exports

- named exports, default exports 두가지 방식이 있음

 

- named export는 export 대상을 명명하여 내보내는 방식

module.exports.add = (a, b) => a + b;
module.export.sub = (a, b) => a - b;

 

또는,

const calculator = require("./calculator.js");  
const { add } = require("./calculator.js");

 

 

3) 특징

- require()는 즉시 스크립트를 실행하는 구조

- top-level await이 불가능하므로 동기적으로 작동

- 동기로 작동하므로 promise를 리턴하지 않고, module.exports에 설정된 값만을 리턴

- import 순서에 따라 스크립트를 실행

 


 

📌 top-level await 이란?
ES2022에서 나온 기능으로, 모듈의 최상위 스코프에서 비동기 동작을 await하여  사용할 수 있다.
 이전에는 async 키워드가 있는 스코프내에서만 await를 통해 해당 스코프에서 비동기 동작이 완료되기까지 블로킹할 수 있었는데
모듈 단위에서 await를 통해 특정 비동기 함수의 동작이 완료되기까지 하위 모듈의 동작을 막을 수 있다.

 

 

💻 예시 코드

//a.js
import fetch  from "node-fetch";
let users;
export default (async () => {
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
    users = resp.json();
})();
export { users };

//b.js
import promise, {users} from './a.js';
  promise.then(() => { 
    console.log('All users:', users);
  });

- a 모듈을 b 모듈에서 사용할 때 a 모듈의 비동기 처리가 완료된 후 사용을 보장하기 위해 위와 같이 처리해야 했음

 

 //a.js
  const resp = await fetch('https://jsonplaceholder.typicode.com/users');
  const users = resp.json();
  export { users};

  //b.js
  import { users } from './a.js';

  console.log(users);
  console.log('In usingAwait module');

- 이렇게 간결하게 비동기 처리 가능

 

 


 

 

2. ESM

- import로 모듈을 접근하고 export로 모듈을 내보내는 ESM 방식

- ESMAScript에 지원하는 방식

- Node14에서는 CJS, MJS(ES Modules)이 공존하는데, 두개를 동시에 사용하기 위해 별도의 처리가 필요하다.

- 모듈 시스템을 CJS(기본값)에서 ESM으로 변경할 시, JS 일부 동작이 변경된다.

 

1. 사용방법

- ESM 방식을 사용하기 위해서는 package.json에 'type:'module'을 설정해야 한다.

// package.json

{
  "type": "module",
}

 

 

2. 문법

- 모듈 접근할 때는 import()

- 모듈 내보낼 때는 export()

 

 

3. 특징

- top-level await를 지원하므로 module loader가 비동기 환경에서 실행된다.

- 그러므로 CJS처럼 스크립트를 바로 실행하지 않고 import, export 구문을 찾아 스크립트를 파싱한다.

- 파싱단계에서 import, export 에러를 감지할 수 있다.

- 모듈을 병렬로 다운로드하지만, 실행은 순차적으로 한다.

- import, export를 지원하지 않는 브라우저가 있어 ESM 사용을 위해 번들러가 필요하다.