"어떤 환경에서 개발하느냐" 와 "호환성과 미래지향성 중 어디에 우선순위를 두느냐"에 달려 있습니다.
| 상황 |
추천 방식 |
| 최신 Node.js 프로젝트 (14버전 이상) |
ES Module (미래지향적) |
| 프론트엔드 (브라우저) 개발 |
ES Module (표준) |
| 기존 Node.js 라이브러리와 호환이 필요 |
CommonJS |
| 빠르게 작성하고 실행해야 할 스크립트 |
CommonJS (간편함) |
| 장점 |
설명 |
| 표준화된 방식 |
모든 브라우저와 Node.js에서 공식적으로 지원 |
| 트리 셰이킹(최적화) 가능 |
불필요한 코드 제거 가능 (프론트엔드에서 중요) |
| 비동기 로딩 가능 |
import()와 top-level await 지원 |
| 미래 지향적 |
Node.js와 모든 모던 JS 도구들이 ESM으로 전환 중 |
| 이유 |
설명 |
| 많은 기존 패키지가 CommonJS로 작성됨 |
require() 기반의 코드와 잘 호환됨 |
| 일부 빌드 도구는 CommonJS에 더 친화적 |
예: ts-node, 일부 Jest 설정 등 |
| ESM 설정이 복잡하거나 번거로운 경우 |
package.json에 "type": "module" 설정 필요 등 |
- 새 프로젝트라면 → 무조건 ES Module
- 기존 프로젝트 유지보수라면 → CommonJS 유지, 필요시 점진적 마이그레이션
- 라이브러리 개발이라면 → 둘 다 지원하는 방식 (dual module) 고려
| 항목 |
CommonJS (require) |
ES Module (import) |
| 문법 |
require, module.exports |
import, export |
| 기본 방식 |
Node.js (기본) |
브라우저 / 최신 Node.js |
| 비동기 로딩 |
❌ 불가능 |
✅ 가능 (top-level await) |
| 동적 import |
제한적 (require) |
✅ import() 가능 |
| 파일 확장자 |
.js |
.mjs 또는 "type":"module" 설정 필요 |
| CommonJS |
ES Module |
const x = require('x') |
import x from 'x' |
module.exports = foo |
export default foo |
exports.foo = bar |
export const foo = bar |
기존 package.json에 type:module을 추가한다.
{
"type": "module"
}
{
"name": "my-test",
"version": "1.0.0",
"description": "",
"type": "module",
..........
}
// legacy.js
const fs = require('fs');
module.exports = { fs };
// modern.mjs
import fs from 'fs';
export { fs };