id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id |
title |
category |
status |
source_trust_level |
verification_status |
created_at |
updated_at |
tags |
tech_stack |
applied_in |
aliases |
| js-module-system-esm-cjs |
JS Module System — ESM vs CJS 그리고 dual package |
Coding |
draft |
B |
conceptual |
2026-05-09 |
2026-05-09 |
| javascript |
| esm |
| cjs |
| package |
| vibe-coding |
|
| language |
applicable_to |
| Node.js / TypeScript / bundler |
|
|
|
| import/export |
| require |
| exports field |
| package.json |
|
JS 모듈 시스템 — ESM vs CJS
2026 현재도 라이브러리 작성자에게 가장 골치 아픈 영역. 신규 코드는 ESM 디폴트, but Node 일부 도구 / 레거시는 CJS 만 — package.json exports 의 dual export 가 표준 답.
📖 핵심 개념
- ESM:
import/export. 정적 분석 가능. tree-shake 친화. 비동기 가능.
- CJS:
require()/module.exports. 동적 (조건부 require). 동기.
- Node.js:
package.json "type": "module" 이면 .js = ESM. 아니면 CJS.
.mjs = 항상 ESM, .cjs = 항상 CJS.
💻 코드 패턴
라이브러리 dual package (ESM + CJS)
TypeScript 빌드 — tsup 또는 unbuild
Subpath exports
null → 임포트 차단.
CJS 안에서 ESM 동적 import
ESM 안에서 CJS import
🤔 의사결정 기준
| 상황 |
형식 |
| 신규 라이브러리 |
ESM-first + dual export |
| 신규 앱 (Next/Vite) |
ESM (bundler 가 처리) |
| Node 서버 (TypeScript) |
ESM with "type": "module" |
| 옛 도구 의존성 다수 (postcss plugin, eslint plugin) |
CJS 또는 dual |
| 동적 require 필요 |
CJS (또는 ESM 의 await import) |
| __dirname / __filename |
ESM 에는 없음 — import.meta.url + fileURLToPath |
❌ 안티패턴
- ESM 라이브러리에
main 만: CJS 사용자 import 시 default 잘못 판정. exports 필드 명시.
- CJS + ESM 양쪽에서 같은 인스턴스 가정: 두 번 evaluate 됨 → 두 인스턴스 (singleton 깨짐).
require("package") 가 ESM-only 패키지: 런타임 에러. 동적 import 로.
exports 필드 빠뜨리고 internal path 노출: 사용자가 import 'pkg/dist/foo' 가능. 명시 차단.
- TypeScript paths 만 의존: 빌드 시 alias 안 풀림. tsc-alias 또는 bundler.
- 순환 import: ESM 도 깨짐. CJS 와 다른 방식으로 깨짐. 의존성 그래프 정리.
- default export 와 named 혼용: tree shake / IDE 자동 import 헷갈림. named 권장.
🤖 LLM 활용 힌트
- 신규 = ESM. 라이브러리는 dual export.
- exports 필드 + types + import + require 4종 세트.
- Node ESM 환경:
import.meta.url, top-level await OK.
🔗 관련 문서