CommonJS(CJS) vs ESModule(ESM)
Node.js 모듈 시스템 완전 분석
블로그 게시글을 HTML로 변환하려고 Marked 라이브러리를 사용하다가 최신 버전(5.x 이상)이 **ES Module(ESM)**을 채택하면서 꽤 당황했다.
현재 내 블로그 환경이 CommonJS(CJS) 방식이라 최신 버전을 바로 쓸 수 없었고, 결국 버전을 4.x로 낮춰서 사용해야 했다.
이 경험을 통해 CJS와 ESM의 차이를 명확히 알아둘 필요성을 느꼈다.
나중에 다시 이런 상황을 겪지 않기 위해 Node.js의 두 가지 모듈 시스템인 CommonJS와 ESModule에 대해 자세히 정리해 두려고 한다.
각 방식의 특징, 장단점, 그리고 어떤 환경에서 어떤 것을 선택해야 하는지 내 머릿속에 확실히 남겨두자.
✅ CommonJS (CJS): Node.js의 전통적인 모듈 시스템
CommonJS는 Node.js 초창기부터 표준처럼 쓰여온 모듈 시스템이다.
Node.js 생태계의 수많은 라이브러리와 패키지가 CJS를 기반으로 만들어졌다.
주로 서버 사이드 개발에서 많이 사용되었다.
✔️ 문법 예시
CJS는 require()
와 module.exports
를 사용해 모듈을 불러오고 내보냅니다.
// math.js (모듈 내보내기)
function add(a, b) {
return a + b;
}
module.exports = add; // add 함수를 모듈로 내보냅니다.
// main.js (모듈 불러오기)
const add = require('./math'); // math.js 모듈을 불러옵니다.
console.log(add(2, 3)); // 5
✔️ 주요 특징
require()
로 모듈 불러오기: 다른 파일의 코드를 가져올 때 사용합니다.module.exports
로 모듈 내보내기: 현재 파일의 특정 변수, 함수, 객체 등을 다른 파일에서 사용할 수 있도록 공개합니다.- 동기 로딩 방식:
require()
를 호출하는 순간 해당 모듈의 코드를 모두 읽어와 실행합니다. 모듈 로딩이 완료될 때까지 다음 코드가 실행되지 않는다는 의미입니다. - Node.js에서 기본 동작: 별도의 설정 없이 Node.js 환경에서 바로 사용할 수 있습니다.
✅ ESModule (ESM): JavaScript의 공식 표준 모듈 시스템
ESModule은 ECMAScript(JavaScript의 표준)에서 공식적으로 채택한 모듈 시스템입니다. 브라우저는 물론이고 Node.js에서도 사용할 수 있는 범용적인 방식이라는 점에서 그 중요성이 점점 커지고 있습니다. 웹팩(Webpack), Vite 같은 최신 빌드 도구들은 ESM을 기반으로 동작하는 경우가 많습니다.
✔️ 문법 예시
ESM은 import
와 export
키워드를 사용합니다. 문법 자체가 훨씬 직관적이죠.
// math.mjs (모듈 내보내기)
export function add(a, b) { // add 함수를 export 키워드로 내보냅니다.
return a + b;
}
// main.mjs (모듈 불러오기)
import { add } from './math.mjs'; // add 함수를 import 키워드로 불러옵니다.
console.log(add(2, 3)); // 5
여기서 .mjs
확장자는 해당 파일이 ESM 방식으로 작성되었음을 명시적으로 나타냅니다.
✔️ 주요 특징
import
/export
문법 사용: 표준화된 문법으로 가독성이 뛰어나고, 정적 분석에 용이합니다.- 비동기 로딩 지원: 모듈을 비동기적으로 불러올 수 있어, 큰 애플리케이션의 초기 로딩 성능을 향상시킬 수 있습니다.
- 브라우저와 호환 가능:
<script type="module">
태그를 사용하면 브라우저에서도 ESM 문법을 바로 사용할 수 있습니다. - 트리 쉐이킹(Tree Shaking)에 유리:
import
와export
는 정적인 분석이 가능하기 때문에, 실제로 사용되지 않는 코드를 최종 번들에서 제외하는 '트리 쉐이킹' 기능을 효율적으로 사용할 수 있습니다. 이는 최종 번들 크기를 줄여 웹 애플리케이션의 로딩 속도를 빠르게 하는 데 크게 기여합니다.
⚙️ Node.js에서 ESModule을 사용하려면?
Node.js에서 ESM을 사용하려면 몇 가지 설정이 필요합니다.
package.json
에"type": "module"
추가: 프로젝트의package.json
파일에 아래와 같이"type": "module"
설정을 추가하면, 해당 프로젝트 내의 모든.js
파일이 기본적으로 ESM로 해석됩니다.{ "name": "my-project", "version": "1.0.0", "type": "module", // 이 설정을 추가해주세요. "main": "index.js", "scripts": { "start": "node index.js" } }
.mjs
확장자 사용:package.json
설정을 변경하지 않고 특정 파일만 ESM으로 사용하고 싶다면,.mjs
확장자를 사용하면 됩니다. Node.js는.mjs
파일을 자동으로 ESM으로 인식합니다. 예를 들어,my-module.mjs
파일은 ESM 문법을 사용할 수 있습니다.
📊 CJS vs ESM: 한눈에 비교하기
두 모듈 시스템의 차이점을 명확하게 이해할 수 있도록 표로 정리해 보았습니다.
항목 | CommonJS (CJS) | ESModule (ESM) |
---|---|---|
사용 문법 | require , module.exports |
import , export |
로딩 방식 | 동기(Synchronous) | 비동기(Asynchronous) |
Node.js 지원 | 기본 지원 | 설정 필요 ("type": "module" 또는 .mjs 확장자) |
브라우저 호환성 | ❌ (별도 번들링 필요) | ✅ ( <script type="module"> 지원) |
트리 쉐이킹 | ❌ (정적 분석 어려움) | ✅ (정적 분석 용이) |
🧠 어떤 모듈 시스템을 선택해야 할까?
어떤 모듈 시스템을 선택할지는 프로젝트의 목적과 환경에 따라 달라집니다.
상황 | 추천 모듈 시스템 | 상세 설명 |
---|---|---|
기존 Node.js 프로젝트 | CommonJS | 이미 CJS로 작성된 코드베이스가 있다면 호환성을 위해 CJS를 유지하는 것이 좋습니다. |
최신 JS 도구 사용, 브라우저 지원, Vite/Webpack 등 사용 | ESModule (ESM) | React, Vue, Svelte와 같은 프론트엔드 프레임워크나 최신 빌드 도구를 사용하는 프로젝트라면 ESM이 필수적입니다. |
React, Vue, Svelte 등 프론트엔드 개발 | ESM | 현대적인 프론트엔드 개발 환경은 대부분 ESM을 기반으로 구축되어 있습니다. |
타입스크립트 기반 최신 백엔드 개발 | ESM 권장 | Node.js 백엔드에서도 TypeScript와 함께 최신 문법과 기능을 사용하고 싶다면 ESM으로 시작하는 것을 권장합니다. |
📌 결론
CommonJS는 여전히 Node.js 생태계에서 중요한 역할을 하고 있지만, Node.js는 점점 ESModule 중심으로 나아가고 있습니다. 특히 최신 JavaScript 생태계의 흐름을 따라가고, 브라우저와 Node.js 환경에서 모두 사용 가능한 범용적인 코드를 작성하고 싶다면 ESM을 기본으로 고려하는 것이 좋습니다.
물론, 기존에 사용하던 패키지가 CJS만 지원하거나, 이미 CJS로 작성된 코드베이스가 있다면 호환성을 위해 CJS를 선택할 수도 있습니다. 하지만 새로운 프로젝트를 시작하거나 기존 프로젝트를 마이그레이션할 계획이라면, ESM의 장점을 최대한 활용하는 방향으로 전환을 고려해 보세요!
🔗 참고 링크
- Node.js ESM 공식 문서: https://nodejs.org/api/esm.html
- MDN Modules 개념: https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Modules