본문 바로가기

언어/Node.js

[ Node.js ] CommonJS vs ESM(ECMAScript Module) 비교

반응형

CommonJS와 ESM(ECMAScript Modules)은 JavaScript에서 모듈을 정의하고 불러오는 두 가지 주요 방식입니다. 두 모듈 시스템 모두 파일 간의 코드를 분리하고 재사용하는 방법을 제공하지만, 그 방식과 동작 원리에서 큰 차이가 있습니다. 아래에서는 CommonJS와 ESM의 주요 차이점을 설명합니다.


1. 역사적 배경

CommonJS

  • 개발 시기: CommonJS는 Node.js에서 사용하기 위해 만들어졌습니다. 브라우저 환경에서는 기본적으로 사용되지 않으며, Node.js의 초기 버전에서 모듈 시스템으로 채택되었습니다.
  • 목적: 서버 사이드 JavaScript의 모듈화를 위해 도입되었습니다.
  • 채택: Node.js가 처음 등장했을 때부터 기본 모듈 시스템으로 사용되어 왔으며, 현재도 대부분의 Node.js 프로젝트에서 널리 사용됩니다.

ECMAScript Modules (ESM)

  • 개발 시기: ESM은 JavaScript 표준화 위원회(ECMA)가 공식적으로 정의한 모듈 시스템입니다. ES6(ECMAScript 2015)에서 도입되었습니다.
  • 목적: 브라우저와 서버 환경 모두에서 통일된 모듈 시스템을 제공하기 위해 도입되었습니다.
  • 채택: ESM은 최신 브라우저와 Node.js 12 이상에서 지원됩니다. ESM은 JavaScript의 표준 모듈 시스템입니다.

2. 문법 차이

CommonJS (Node.js에서 사용)

  • 모듈 불러오기: require() 함수로 모듈을 불러옵니다.
  • 모듈 내보내기: module.exports 또는 exports 객체를 사용해 모듈을 내보냅니다.
// 불러오기 (CommonJS)
const myModule = require('./myModule');

// 내보내기 (CommonJS)
module.exports = {
  myFunction: function() { ... }
};

ESM (ECMAScript 모듈)

  • 모듈 불러오기: import 키워드를 사용해 모듈을 불러옵니다.
  • 모듈 내보내기: export 또는 export default를 사용해 모듈을 내보냅니다.
// 불러오기 (ESM)
import myModule from './myModule.js';

// 내보내기 (ESM)
export default function myFunction() { ... };
export const myVariable = 42;

주요 차이점

  • require() vs import: CommonJS는 함수 형태인 require()로 모듈을 동적으로 불러오고, ESM은 import를 사용해 정적으로 모듈을 불러옵니다.
  • 동적 로딩: CommonJS는 동적으로 모듈을 불러오는 것이 가능하지만, ESM은 기본적으로 정적 분석이 요구됩니다. 다만, ESM에서도 import() 함수로 동적 로딩이 가능합니다.

3. 모듈 내보내기 방식

CommonJS

  • CommonJS에서는 module.exports 객체를 사용해 모듈을 내보냅니다. 이는 기본적으로 하나의 객체를 내보내는 방식입니다.
// 내보내기
module.exports = {
  myFunction: function() { ... }
};
  • 여러 객체를 내보낼 때 exports 객체를 사용해 개별 속성으로 내보낼 수 있습니다.
exports.myFunction = function() { ... };
exports.myVariable = 42;

ESM

  • ESM에서는 exportexport default를 사용합니다. export는 여러 개의 개별적인 변수나 함수를 내보낼 수 있습니다.
// 여러 개 내보내기
export const myFunction = () => { ... };
export const myVariable = 42;
  • export default는 파일당 단일 기본 모듈을 내보낼 수 있도록 설계되었습니다.
// 기본 내보내기
export default function myFunction() { ... };

4. 로딩 방식

CommonJS: 동기적 로딩

  • require()동기적으로 동작하며, 모듈이 로드될 때까지 코드 실행이 중단됩니다.
  • Node.js에서는 이 방식이 서버 사이드 환경에서 성능 문제를 일으키지 않지만, 브라우저 환경에서는 적합하지 않을 수 있습니다.

ESM: 비동기적 로딩

  • ESM은 비동기적으로 모듈을 로드합니다. 특히, 브라우저 환경에서 비동기 로딩이 필수적이기 때문에 ESM은 기본적으로 비동기 방식으로 동작합니다.
  • ESM은 JavaScript 엔진이 컴파일 타임에 모듈을 분석하여 필요한 모듈을 미리 가져오기 때문에, 최적화에 유리합니다.

5. 동적 로딩 지원

CommonJS

  • CommonJS는 require() 자체가 함수이기 때문에 동적으로 모듈을 불러오는 것이 매우 쉽습니다. 조건문 안에서 require()를 사용해 특정 상황에서만 모듈을 불러오는 것이 가능합니다.
if (condition) {
  const myModule = require('./myModule');
}

ESM

  • ESM의 import는 정적 분석이 필요하기 때문에 기본적으로 파일 최상단에서 사용해야 하며, 동적 로딩이 불가능합니다.
  • 그러나, ES2020부터 도입된 동적 import() 문법을 사용하면 ESM에서도 모듈을 동적으로 로딩할 수 있습니다. 이 방식은 Promise를 반환합니다.
// 동적 import
import('./myModule.js').then(module => {
  module.myFunction();
});

6. 트리 셰이킹(Tree Shaking)

CommonJS

  • CommonJS는 런타임에 require()로 모듈을 불러오기 때문에 트리 셰이킹(필요 없는 코드를 제거하는 최적화 기법)이 불가능합니다. 모든 모듈을 불러온 후, 사용되지 않더라도 포함됩니다.

ESM

  • ESM은 정적 분석을 기반으로 하므로 트리 셰이킹이 가능합니다. 코드 번들러(Webpack, Rollup 등)는 사용되지 않은 모듈을 컴파일 단계에서 제거할 수 있어 최적화된 번들 크기를 제공합니다.

7. 호환성 및 파일 확장자

CommonJS

  • Node.js는 CommonJS를 기본 모듈 시스템으로 사용하며, 모든 Node.js 버전에서 기본적으로 지원됩니다.
  • CommonJS 파일은 일반적으로 .js 확장자를 사용합니다.

ESM

  • Node.js 12+ 버전에서 ESM이 도입되었으며, Node.js에서 사용하려면 두 가지 방법 중 하나를 따라야 합니다:
    1. 파일 확장자를 .mjs로 사용.
    2. package.json 파일에서 "type": "module"을 설정.
  • 브라우저 환경에서도 ESM이 기본적으로 지원되며, <script type="module"> 태그를 사용해 ESM을 로드할 수 있습니다.
<script type="module">
  import myModule from './myModule.js';
</script>

8. 요약 비교

특징 CommonJS ESM (ECMAScript Modules)
사용 환경 Node.js Node.js, 브라우저
모듈 불러오기 require() import
모듈 내보내기 module.exports, exports export, export default
로딩 방식 동기적 비동기적
동적 로딩 가능 (require()로 동적 로딩) 가능 (import()로 비동기 로딩)
트리 셰이킹 지원 불가능 가능
파일 확장자 .js .mjs 또는 "type": "module"
호환성 모든 Node.js 버전 Node.js 12+, 브라우저

9. 결론

  • CommonJS는 Node.js 환경에서 오래된 모듈 시스템이며, 대부분의 기존 Node.js 프로젝트에서 여전히 사용되고 있습니다.
  • ESM은 최신 JavaScript 표준 모듈 시스템으로, 브라우저와 Node.js 모두에서 통일된 방식으로 사용됩니다. ESM은 더 많은 최적화 가능성을 제공하며, 특히 트리 셰이킹과 같은 최적화 기법을 지원하는 점에서 유리합니다.
반응형