타입스크립트 교과서
라는 책을 통해 타입스크립트에 대해 공부하던 중, 책에서 언급된 CommonJS
와 ECMAScript 모듈
이라는 개념에 대해 이해가 부족하여 블로그에 정리해보고 싶다 생각하여 선정하게 됐습니다. CommonJS
와 ECMAScript 모듈
는 한줄로 설명하자면 모듈 시스템의 종류입니다.
모듈 시스템? 모듈들을 구성하고 관리하여 재사용성과 코드의 구조화를 도와주는 도구
모듈? 독립적으로 작동하는 코드 조각
코드를 조직화하고 재사용 가능한 부품으로 분리하여 개발자가 애플리케이션을 효율적으로 유지하고 관리할 수 있도록 돕습니다.
CommonJS 모듈은 Node.js
에서 JavaScript 코드를 패키징하는 최초의 방식입니다.
기본적으로 Node.js는 다음과 같은 파일들을 CommonJS 모듈로 취급합니다:
.cjs
확장자를 가진 파일들package.json
파일에 최상위 필드 "type"
이 "commonjs"
로 설정된 경우, .js
확장자를 가진 파일들package.json
파일에 최상위 필드 "type"
이 없거나 상위 폴더에 package.json
이 없는 경우, .js
확장자를 가진 파일이나 확장자가 없는 파일들(단, 파일에 ECMAScript Modules로 평가되지 않으면 에러가 나는 구문이 포함되지 않은 경우)"type"
필드를 포함하는 것을 권장한다. 패키지의 타입을 명시적으로 지정하면, 빌드 도구와 로더가 패키지의 파일을 어떻게 해석해야 할지 더 쉽게 판단할 수 있기 때문이다..mjs
, .cjs
, .json
, .node
또는 .js
가 아닌 확장자를 가진 파일들package.json
파일에 최상위 필드 "type"
이 "module"
로 설정된 경우, require()
로 포함되는 경우에만 CommonJS 모듈로 인식되며, 명령 줄에서 프로그램의 진입점으로 사용되는 경우는 제외합니다.require()
를 호출하면 항상 CommonJS 모듈 로더를 사용합니다.import()
를 호출하면 항상 ECMAScript 모듈 로더를 사용합니다.ECMAScript Moduels는 ECMAScript 6(ES6)에서 도입된 표준 모듈 시스템입니다. ECMAScript 모듈은 재사용을 위해 JavaScript 코드를 패키징하는 공식 표준 형식입니다. 모듈은 다양한 import
와 export
구문을 사용하여 정의됩니다.
다음과 같은 방법으로 JavaScript를 ECMAScript Modules로 해석하도록 Node.js에 알릴 수 있습니다:
.mjs
파일 확장자를 사용합니다.package.json
파일에 "type"
필드를 "module"
로 설정합니다.--input-type
플래그를 "module"
값으로 설정합니다.node --input-type=module -e "import { add } from './math.mjs'; console.log(add(2, 3));"
--experimental-default-type
플래그를 "module"
값으로 설정합니다.node --input-type=module -e "import { add } from './math.mjs'; console.log(add(2, 3));"
JavaScript를 CommonJS 모듈로 해석하도록 Node.js에 알릴 수 있는 방법:
.cjs
파일 확장자를 사용package.json
파일에 "type"
필드를 "commonjs"
로 설정--input-type
플래그를 "commonjs"
값으로 설정node --input-type=commonjs -e "const add = require('./math.cjs'); console.log(add(2, 3));"
--experimental-default-type
플래그를 "commonjs"
값으로 설정node --experimental-default-type=commonjs script.js
내보내기 및 가져오기 구문
CommonJS
module.exports
또는 exports
객체를 사용하여 모듈에서 변수, 함수, 객체 등을 내보냅니다. require()
함수를 사용하여 다른 모듈에서 내보낸 항목을 가져옵니다.
// math.js
function add(a, b) {
return a + b;
}
module.exports = add;
// app.js
const add = require('./math');
console.log(add(2, 8)); // 10
```
ECMAScript Modules
export
키워드를 사용하여 변수, 함수, 객체 등을 외부로 내보냅니다. import
키워드를 사용하여 다른 모듈에서 내보낸 항목을 가져옵니다.
// math.mjs
export function add(a, b) {
return a + b;
}
// app.mjs
import { add } from './math.mjs';
console.log(add(2, 8)); // 10
```
동기 vs 비동기
require()
함수를 사용하여 모듈을 가져오기 때문에, 모듈이 필요할 때마다 코드가 멈추고 기다리는 경우가 있을 수 있습니다.import
구문이 비동기적으로 동작할 수 있어, 필요할 때만 모듈을 가져오고 사용할 수 있습니다.기능성
Node.js 애플리케이션의 컨텍스트? Node.js 애플리케이션의 실행 환경이나 범위를 의미합니다.
컴파일
네이티브로 지원되는 환경? 브라우저나 Node.js 같은 최신 자바스크립트 엔진이 ECMAScript Moduels를 직접 지원하는 것을 의미합니다.
의존성
CommonJS는 AMD 호환성이 있어 Node.js 및 브라우저에서 사용할 수 있습니다.
ECMAScript Modules는 AMD 호환성이 없지만 webpack 모듈 로더를 통해 브라우저에서 지원됩니다.
CommonJS는 몇 가지 종속성(Ex. Node.js, npm 등)이 필요합니다.
- CommonJS 모듈은 Node.js 환경과 npm 패키지 관리자에 의존합니다.
ECMAScript Modules는 모듈 로더를 제외하고는 추가 종속성이 없습니다.
- ECMAScript Modules는 브라우저와 Node.js에서 기본적으로 지원되므로 추가 종속성이 없지만, 복잡한 프로젝트에서는 Webpack과 같은 도구가 필요할 수 있습니다.
AMD? Asynchronous Module Definition, JS의 모듈 정의를 위한 표준 중 하나입니다. 브라우저 환경에서 비동기적으로 모듈을 로드하고 정의하는 방법을 제공하여 모듈화를 촉진하는 모듈 시스템입니다.
webpack? 모듈 번들러로, JS 애플리케이션을 구성하는 여러 모듈을 번들링하여 단일 파일로 생성합니다. 이를 통해 모듈 간 의존성을 관리하고 브라우저에서 사용할 수 있는 형식으로 변환합니다.
모듈 번들러? 여러 개의 모듈을 하나의 번들(묶음)로 만들어주는 도구입니다.
번들링? 모듈 번들러가 수행하는 작업 중 하나로, 애플리케이션에서 사용하는 모든 모듈을 결합하여 하나의 번들 파일로 생성하는 과정을 말합니다.
아래 두 가지 경우에 대해 고려해 볼 수 있습니다:
Modules:CommonJS modules - Node.js v22.3.0 documentation
Modules:ECMAScript modules - Node.js v22.3.0 documentation
CommonJS vs ES Modules in Node.js
JavaScript Module System