백엔드/Node.js

CommonJS(CJS), ES Module(ESM) 차이점과 특징

SparkIT 2024. 11. 20. 20:49

Node.js에서 모듈을 호출하는 방식은 2 가지 존재합니다. CommonJS 방식과 ES Module 방식입니다. CommonJS는 기존에 node 쪽에서 사용되던 근본 방식으로 require 명령어로 모듈을 호출합니다. ES Module은 비교적 최근인 node.js 12 버전부터 추가된 방식으로 import 명령어로 모듈을 호출합니다. 오늘은 이런 2 가지 방식의 특징과 차이점에 대해 알아보겠습니다.

 

참조 블로그

 

CommonJS와 ESM에 모두 대응하는 라이브러리 개발하기: exports field

Node.js에는 두 가지 Module System이 존재합니다. 토스 프론트엔드 챕터에서 운영하는 100개가 넘는 라이브러리들은 그것에 어떻게 대응하고 있을까요?

toss.tech

 


CommonJS(CJS)

예제

// add.js
module.exports.add = (x, y) => x + y;

// main.js
const { add } = require('./add');

add(1, 2);

CommonJS 방식의 간단한 예제입니다. module.exports로 모듈을 내보내고 require로 모듈을 호출합니다.

 

특징

  • Node.js의 기본 모듈 시스템입니다.
  • 동기적으로 동작하며, require와 module.exports를 사용해 모듈을 가져오고 내보냅니다.
  • ES6 이전부터 사용되던 방식으로, 오래된 프로젝트나 라이브러리에서 여전히 널리 사용됩니다.
  • 모든 파일이 즉시 실행되어 모듈 로드가 간단하고 직관적입니다.
  • .cjs 확장자를 사용해 명시적으로 작성 가능합니다.

 

 


ES Module(ESM)

예제

// add.js
export function add(x, y) {
  return x + y
}

// main.js
import { add } from './add.js';

add(1, 2);

ES Module 방식의 간단한 예제입니다. export로 모듈을 내보내고 import로 모듈을 호출합니다.

특징

  • ES6 표준으로 정의된 모듈 시스템입니다.
  • import와 export를 사용해 모듈을 가져오고 내보냅니다.
  • 비동기적 로딩을 지원하며, 더 유연하고 최신 JavaScript 기능과 통합됩니다.
  • Node.js에서는. mjs 확장자나 package.json에 "type": "module" 설정으로 활성화해야 합니다.

 


CommonJS, ES Module 적용하기( 백엔드: NestJS 예제 )

저는 백엔드 개발에 더 집중해서 공부하고 있기 때문에 백엔드 프레임워크 중 하나인 NestJS에서 CommonJS 방식과 ES Module 방식을 어떻게 사용하는지에 대해 알아보았습니다.

 

CommonJS 사용하기

NestJS는 기본적으로 CommonJS 방식이 적용됩니다. 이때 기본적인 nest 명령어로 생성된 NestJS 코드에서는 import/export 문법으로 모듈을 호출하는 모습을 볼 수 있어 ES Module 방식이 사용된다고 오해할 수 있습니다. 하지만 이런 typescript 코드는 결과적으로 컴파일 후에는 CommonJS 방식으로 변환됩니다.

만약, 직접적으로 CommonJS 방식을 적용하고 싶다면 tsconfig.json을 다음과 같이 설정합니다.

# tsconfig.json

{
  "compilerOptions": {
    "module": "CommonJS",  // CommonJS 모듈 사용
    "target": "ES2020",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

 

ES Module 사용하기

NestJS에서 ES Module 방식을 사용하기 위해서는 tsconfig.json을 다음과 같이 설정합니다.

# tsconfig.json

{
  "compilerOptions": {
    "module": "ESNext", // 또는 "ES6"로 설정
    "target": "ES2020",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  }
}

( 여기서 esModuleInterop 옵션은 CommonJS 모듈을 ES6 import 방식으로 호출할 수 있도록 도와주는 옵셥입니다. )

또한 package.json 설정에도 다음과 같은 내용을 추가합니다.

# package.json

{
  "type": "module"
}

 

CommonJS + ES Module 둘 다 사용하기

기본적으로 CommonJS 방식에서는 ES Module 방식을 지원하지 않습니다. 그렇기 때문에 2 방식을 모두 사용하기 위해서는 일단 ES Module 방식을 사용하도록 해야 합니다. 먼저 package.json에 type 옵션을 module로 설정합니다.

# package.json

{
  "type": "module"
}

 

이때 require 명령어를 사용하면 .cjs 확장자를 이용해 명시적으로 CommonJS 방식을 사용하는 모듈이 있다면, 해당 모듈을 CommonJS 방식으로 호출해 사용가능합니다.

 


요약

  CommonJS ES Module
호출 명령어 require import
모듈 호출 방식 동기적 비동기적
트리 셰이킹(Tree Shaking) 어려움 쉬움
확장자 .cjs .mjs