
안녕하세요! 웹 YB 한승우입니다.
때때로 프로젝트를 초기화하고 pnpm init을 실행한 후, index.js 파일에서 다른 파일이나 라이브러리를 import하려고 하면 이런 오류를 마주치게 됩니다.
❗ Cannot use import statement outside a module
→ package.json의 type을 module로 설정하라는 오류
저도 처음에는 무슨 말인지 모르고 그냥 "type": "module"을 넣고 넘어갔는데,
문득 이 type 설정이 정확히 어떤 차이를 만들어낼지 궁금증이 생기게 되었습니다.
그래서 이번 글에서는 CommonJS(CJS)와 ESModules(ESM)의 동작 방식과 type 설정이 모듈 시스템에 어떤 영향을 주는지 정리해 보았습니다.
1. package.json의 type 속성
{
"type": "commonjs"
}
index.js
package.json
- type의 기본값은 "commonjs"이다.
이 경우, index.js는 CommonJS 방식으로 해석되며 .js 파일은 자동으로 .cjs처럼 작동한다. - 반대로 "type": "module"로 설정하면 ESM 방식으로 해석되며, .js 파일은 .mjs처럼 작동하게 된다.
즉, 동일한 .js 확장자라도 type 값에 따라 완전히 다른 방식으로 동작하게 된다는 점을 주의해야 한다.
그렇다면 CommonJS와 ESM의 동작 방식은 어떨까?
2. CommonJS의 구조와 특징
// math.cjs
module.exports.math = {
add(a, b) {
return a + b;
},
};
// index.cjs
const { math } = require("./math.cjs");
console.log(math.add(1, 2));
- 모듈을 require()로 가져오고, module.exports로 내보낸다.
- 런타임 분석이기 때문에 아래처럼 동적으로 모듈을 불러오는 것도 가능하다.
// add.cjs
module.exports = {
add(a, b) {
return a + b;
},
};
// index.cjs
const fileName = "add.cjs";
const { add } = require(`./${fileName}`);
console.log(add(1, 2));
이는 CJS가 런타임에서 모듈 관계를 파악하기 때문이다.
3. ESModules (ESM)의 구조와 특징
// math.mjs
export function add(a, b) {
return a + b;
}
// index.mjs
import { add } from "./math.mjs";
console.log(add(1, 2));
- import를 사용하여 모듈을 불러오고 export를 이용하여 모듈을 내보낸다.
- 컴파일 타임 분석(정적 분석) 기반 → 동적 import가 불가능
하지만 정적 분석을 하기 때문에 Tree-shaking을 할 수 있어 자바스크립트 번들의 크기는 줄어든다.
또한 ESM에서는 CJS를 import 할 수 있지만 CJS에서는 ESM을 require 할 수 없다. 이는 ESM만 Top-level Await를 지원하기 때문이다.
ESM → CJS는 import 가능
CJS → ESM은 require 불가능
4. 요약
| 구분 | CommonJS (CJS) | EsModules(ESM) |
| 분석시점 | 런타임 | 컴파일타임 |
| Tree-shaking | 불가능 | 가 |
| 동작 방식 | 동기 | 비동기 |
| 문법 | require, module.exports | import, export |
| 파일 확장자 | .cjs / .js | .mjs / .js |
| Top-level await | 지원 X | 지 |
5. 마무리하며
오류가 발생했을 때는 무심코 "type": "module"을 넣고 넘어가는 경우가 많았지만, 이번에 이를 계기로 각 모듈 시스템의 동작 원리와 구조적 차이를 이해하게 되어 좋았다.
이해하고 나니 앞으로는 프로젝트에 맞는 모듈 시스템을 선택하고 설정할 수 있을 것 같다.
아래 토스의 글이 정말 잘 정리되어 있으니 한 번씩 읽어보는 것을 추천한다.
6. 참고
'4주차' 카테고리의 다른 글
| 대중적인 API instance 세팅과 고려해야할 점! (0) | 2025.05.13 |
|---|---|
| 네이밍 규칙 (1) | 2025.05.13 |
| Zustand 전역 상태 관리: 개념부터 실무까지 한 번에 정리 (0) | 2025.05.13 |
| Tailwind CSS 버전 정리 (0) | 2025.05.13 |
| Tanstack Query (0) | 2025.05.13 |