CommonJS와 ES Modules

GwangSoo·2024년 9월 30일
0

개인공부

목록 보기
11/34
post-thumbnail

pnpm init 명령어 실행 후 index.js 파일에서 작업을 하다 보면 라이브러리나 다른 파일을 import를 했을 때 package.jsontypemodule로 설정하라는 오류가 뜬다.

오늘은 package.json에서 type의 값에 따라 모듈 시스템을 어떻게 인식하는지, 그리고 각각의 차이점은 무엇인지에 대해 알아보겠다. 시간이 없다면 요약만 봐도 좋다.

package.json의 type

{
	"type": "commonjs"
}
index.js
package.json

package.json에 있는 type의 기본 값은 commonjs이다. 이때는 CommonJS 모듈 시스템으로 인식하고 파일명을 index.js로 지어도 index.cjs로 인식하게 된다.

반면 type의 값을 module로 설정하게 되면 ESM 모듈 시스템으로 인식하고 파일명을 index.mjs로 인식하게 된다.

그렇다면 CommonJS와 ESM의 동작 방식은 어떨까?

CJS(CommonJS)

// math.cjs
module.exports.math = {
  add(a, b) {
    return a + b;
  },
};
// index.cjs
const { math } = require("./math.cjs");

console.log(math.add(1, 2)); // 3

require를 사용하여 모듈을 불러오고 module.exports를 이용하여 모듈을 내보낸다.

또한 동적으로 모듈을 가져올 수 있다.

// add.cjs
module.exports = {
  add(a, b) {
    return a + b;
  },
};
// index.cjs
const fileName = "add.cjs";
const { add } = require(`./${fileName}`);

console.log(add(1, 2)); // 3

이는 CJS가 런타임에서 모듈 관계를 파악하기 때문이다.

ESM(ES Modules)

// math.mjs
export function add(a, b) {
  return a + b;
}
// index.mjs
import { add } from "./math.mjs";

console.log(add(1, 2));

import를 사용하여 모듈을 불러오고 export를 이용하여 모듈을 내보낸다.

CJS와는 다르게 ESM은 컴파일 타임에 분석(정적 분석)되기 때문에 동적으로 모듈을 가져오지 못한다. 하지만 정적 분석을 하기 때문에 Tree-shaking을 할 수 있어 자바스크립트 번들의 크기는 줄어든다.

또한 ESM에서는 CJS를 import 할 수 있지만 CJS에서는 ESM을 require 할 수 없다. 이는 ESM만 Top-level Await를 지원하기 때문이다.

요약

분석 시점Tree-shaking 여부동작모듈 가져오기/내보내기
CJS런타임 타임O동기require/module.exports
ESM컴파일 타임X비동기import/export

마무리하며

오류가 나면 그냥 무심코 package.jsontype을 지정해 주고 넘어갔었는데, 이번 기회에 둘의 차이에 대해 공부해 보는 계기가 되어 좋았다. 토스의 글이 정말 잘 정리되어 있으니 한 번씩 읽어보는 것을 추천한다.

참고

0개의 댓글