[Node.js] Node.js 모듈 시스템: CommonJS vs ESM

artp·2025년 9월 24일

node.js

목록 보기
8/9
post-thumbnail

Node.js 모듈 시스템: CommonJS vs ESM

1. 모듈 시스템이란?

모듈(Module)은 특정 기능과 관련된 함수, 변수, 클래스를 하나로 묶어 독립적으로 관리하고 재사용할 수 있도록 만든 코드 단위입니다. 모듈 시스템은 이러한 모듈을 만들고, 다른 파일에서 가져와서(import) 사용하며, 외부에서 사용할 수 있도록 내보내는(export) 방식을 정의하는 규칙입니다.

모듈 시스템을 사용하면 다음과 같은 장점이 있습니다.

  • 코드 재사용성: 한번 작성한 코드를 여러 곳에서 쉽게 가져와 사용할 수 있습니다.
  • 네임스페이스 관리: 각 파일이 독립적인 스코프(scope)를 가지므로, 전역 변수 충돌 문제를 방지합니다.
  • 유지보수 용이성: 기능 단위로 코드가 분리되어 있어 특정 기능을 찾고 수정하기 쉽습니다.

Node.js에서는 주로 두 가지 모듈 시스템이 사용됩니다:

CommonJSECMAScript Modules(ESM).

2. CommonJS (CJS)

CommonJS는 Node.js의 전통적인 모듈 시스템입니다. 각 파일은 그 자체로 하나의 모듈이며, 동기적으로(synchronously) 모듈을 불러옵니다.

  • 주요 키워드: require (모듈 가져오기), module.exports 또는 exports (모듈 내보내기)

CommonJS 예시 코드

math-cjs.js (기능을 내보내는 파일)

// math-cjs.js
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

const PI = 3.14;

module.exports = {
  add,
  subtract,
  PI,
};

app-cjs.js (모듈을 가져와 사용하는 파일)

// app-cjs.js
const math = require("./math-cjs.js");

console.log("CommonJS 방식:");
console.log("3 + 5 =", math.add(3, 5));
console.log("10 - 7 =", math.subtract(10, 7));
console.log("PI =", math.PI);

3. ECMAScript Modules (ESM)

ESM은 JavaScript의 공식 표준 모듈 시스템으로, 현재 Node.js 생태계의 사실상 표준입니다. 비동기적으로 모듈을 불러와 성능에 이점이 있습니다.

  • 주요 키워드: import (모듈 가져오기), export (모듈 내보내기)
  • Node.js에서 ESM 사용법:
    • package.json 파일에 "type": "module"을 추가합니다. (가장 일반적인 방법)
    • 또는 파일 확장자를 .mjs로 사용합니다.

ESM 주의사항 및 주요 팁

  1. 파일 확장자 생략 불가

    • import 경로를 지정할 때 반드시 파일 확장자(.js, .mjs 등)를 포함해야 합니다. CommonJS의 require처럼 생략할 수 없습니다.
    • import utils from './utils'; (X)
    • import utils from './utils.js'; (O)
  2. export default (기본 내보내기)

    • 파일(모듈)에서 단 하나만 존재할 수 있습니다.
    • 이 모듈의 가장 핵심적이거나 대표적인 기능을 내보낼 때 주로 사용합니다.
    • import 시 중괄호({}) 없이 원하는 이름으로 가져올 수 있어 편리합니다.
  3. export (이름 지정 내보내기)

    • 모듈에서 여러 개를 내보낼 수 있습니다.
    • import 시 반드시 중괄호({})를 사용하고, 내보낸 이름과 동일하게 가져와야 합니다.

ESM 예시 코드

math-esm.js (기능을 내보내는 파일)

// math-esm.js

// 1. 이름 지정 내보내기 (Named Exports)
export const PI = 3.14;
export function add(a, b) {
  return a + b;
}

// 2. 기본 내보내기 (Default Export)
// 보통 모듈을 대표하는 하나의 기능이나 객체를 내보낼 때 사용합니다.
const mathUtils = {
  subtract: (a, b) => a - b,
  multiply: (a, b) => a * b,
};
export default mathUtils;

app-esm.js (모듈을 가져와 사용하는 파일)

// app-esm.js

// 'default export'는 중괄호 없이 원하는 이름(여기서는 myUtils)으로 가져옵니다.
import myUtils from './math-esm.js';

// 'named export'는 중괄호를 사용해 이름 그대로 가져옵니다.
import { PI, add } from './math-esm.js';

console.log("ESM 방식:");
console.log("Default Export (subtract):", myUtils.subtract(10, 7)); // 3
console.log("Named Export (add):", add(3, 5));                      // 8
console.log("Named Export (PI):", PI);                             // 3.14

4. 주요 차이점 요약

구분 (Category)CommonJS (CJS)ECMAScript Modules (ESM)
문법require() / module.exportsimport / export
로딩 방식동기적 (Synchronous): 코드가 실행되는 시점에 모듈을 불러옴비동기적 (Asynchronous): 파싱 단계에서 미리 모듈 관계를 분석
import 경로확장자 생략 가능확장자 필수 포함
this 컨텍스트모듈 최상위 스코프의 thisexports 객체모듈 최상위 스코프의 thisundefined
사용 환경레거시 Node.js최신 브라우저 및 Node.js (현재 표준)

5. 언제 무엇을 사용해야 할까?

  • CommonJS:

    • ESM을 지원하지 않는 오래된 라이브러리나 도구(일부 테스트 프레임워크 등)를 사용해야 하는 경우
    • 기존에 CommonJS로 작성된 대규모 레거시 프로젝트를 유지보수하는 경우
  • ESM:

    • 모든 새로운 Node.js 프로젝트에서 사용을 강력히 권장합니다.
    • 프론트엔드(React, Vue 등)와 백엔드 간에 코드를 공유할 때 일관성을 유지할 수 있습니다.
    • 정적 분석의 이점을 통해 트리 쉐이킹(Tree Shaking) 등 빌드 최적화를 극대화할 수 있습니다.
profile
donggyun_ee

0개의 댓글