1. 개요
Node.js 코드에서 require도 보이고 import도 보이는 프로젝트가 있다. 둘 다 “모듈을 불러온다”는 목적은 같지만 동작 방식이 근본적으로 다르다. CommonJS(CJS)는 런타임에 동기적으로 로드하고, ESM은 정적으로 분석돼 로드 시점이 다르다. 이 차이를 모르면 “왜 이 파일에서는 require가 안 먹히지” 같은 에러에서 헤맨다. JavaScript 기초 시리즈의 마지막 편이다.
2. 핵심 내용
2-1. CommonJS: 런타임 동기 로드
Node.js가 원래 쓰던 방식이다. require는 함수 호출이라 코드 어디서나(조건문 안에서도) 부를 수 있고, 호출되는 그 순간 동기적으로 파일을 읽어 실행한다.
// math.js
module.exports = { add: (a, b) => a + b };
// main.js
const { add } = require("./math");
if (condition) {
const extra = require("./extra"); // 조건부 로드도 가능
}module.exports에 담은 객체가 통째로 반환된다.
2-2. ESM: 정적 구조, 트리 셰이킹 가능
ES2015에서 표준화된 방식이다. import/export는 파일의 최상단에서만 쓸 수 있고(동적 import()는 예외), 코드를 실행하기 전에 엔진이 먼저 어떤 모듈이 어떤 걸 내보내고 가져오는지 정적으로 분석한다.
// math.mjs
export const add = (a, b) => a + b;
// main.mjs
import { add } from "./math.mjs";이 정적 구조 덕분에 번들러가 “실제로 안 쓰는 export”를 빌드 시점에 제거할 수 있다(트리 셰이킹). CommonJS는 require가 런타임에 뭘 반환할지 실행해봐야 알기 때문에 이게 어렵다.
2-3. 왜 섞으면 문제가 나나
Node.js는 파일 확장자와 package.json의 type 필드로 이 파일이 CJS인지 ESM인지 정한다(.mjs는 항상 ESM, .cjs는 항상 CJS, .js는 type 필드를 따른다). 문제는 두 시스템의 로드 타이밍이 다르다는 거다.
- ESM에서 CJS를 불러오는 건 대체로 된다.
import pkg from "commonjs-package"(단, named export는 정적 분석이 안 되니module.exports의 최상위 키만 잡아준다, 완전하지 않을 수 있다) - CJS에서 ESM을 require로 바로 불러오는 건 안 된다. ESM은 비동기로 로드되는데
require는 동기 함수라서다.require가 Promise를 반환할 수는 없다.
// esm-only.mjs (export default 만 있는 순수 ESM 패키지)
const mod = require("esm-only"); // Error [ERR_REQUIRE_ESM]이런 패키지를 CJS 파일에서 쓰려면 동적 import()(Promise를 반환한다)를 쓰거나, 프로젝트 자체를 ESM으로 옮겨야 한다.
2-4. this와 top-level 동작도 다르다
CJS 모듈 최상단의 this는 module.exports를 가리키지만, ESM 모듈 최상단의 this는 undefined다. 또 CJS는 __dirname, __filename을 기본 제공하지만 ESM에는 없다(import.meta.url로 대체해야 한다). 두 시스템을 섞을 때 이런 전역처럼 보이는 것들이 조용히 사라지는 게 실수의 원인이 된다.
3. 마무리
요약
- CJS(
require)는 런타임 동기 로드, ESM(import)은 정적 분석 기반 로드다- ESM의 정적 구조 덕분에 트리 셰이킹이 가능하다, CJS는 어렵다
- CJS 파일에서 순수 ESM 패키지를 require로 바로 못 부른다, 동적
import()나 프로젝트 전환이 필요하다__dirname/__filename/최상단this는 CJS에만 있다, ESM은import.meta.url을 쓴다
이 시리즈는 여기까지다. 이벤트 루프, 클로저, this, 프로토타입/class, Promise/async, 동등 비교, 모듈 시스템까지 — 프레임워크를 걷어내고 봐야 보이는 것들이었다.