[JS] CommonJS와 ECMAScript Modules란?

soleil_lucy·2024년 6월 12일
0

🤔 CommonJS와 ECMAScript Moudules에 대한 주제를 선정한 이유?

타입스크립트 교과서라는 책을 통해 타입스크립트에 대해 공부하던 중, 책에서 언급된 CommonJSECMAScript 모듈 이라는 개념에 대해 이해가 부족하여 블로그에 정리해보고 싶다 생각하여 선정하게 됐습니다. CommonJSECMAScript 모듈는 한줄로 설명하자면 모듈 시스템의 종류입니다.

모듈 시스템? 모듈들을 구성하고 관리하여 재사용성과 코드의 구조화를 도와주는 도구

모듈? 독립적으로 작동하는 코드 조각

🤔 모듈 시스템이 필요한 이유?

코드를 조직화하고 재사용 가능한 부품으로 분리하여 개발자가 애플리케이션을 효율적으로 유지하고 관리할 수 있도록 돕습니다.

🤔 CommonJS란?

CommonJS 모듈은 Node.js에서 JavaScript 코드를 패키징하는 최초의 방식입니다.

👽 CommonJS 모듈 활성화 방법

기본적으로 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 모듈로 인식되며, 명령 줄에서 프로그램의 진입점으로 사용되는 경우는 제외합니다.

👽 CommonJS 모듈 로더를 사용하는 경우?

  • require()를 호출하면 항상 CommonJS 모듈 로더를 사용합니다.
  • import()를 호출하면 항상 ECMAScript 모듈 로더를 사용합니다.

🤔 ECMAScript Modules(ESM)이란?

ECMAScript Moduels는 ECMAScript 6(ES6)에서 도입된 표준 모듈 시스템입니다. ECMAScript 모듈은 재사용을 위해 JavaScript 코드를 패키징하는 공식 표준 형식입니다. 모듈은 다양한 importexport 구문을 사용하여 정의됩니다.

👽 ECMAScript 모듈로 해석

다음과 같은 방법으로 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));"

👽 CommonJS 모듈로 해석

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와 ECMAScript Modules의 차이?

  1. 내보내기 및 가져오기 구문

    • 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
      		```
      
  2. 동기 vs 비동기

    • CommonJS는 동기적인 require() 함수를 사용하여 모듈을 가져오기 때문에, 모듈이 필요할 때마다 코드가 멈추고 기다리는 경우가 있을 수 있습니다.
    • ECMAScript Modules는 import 구문이 비동기적으로 동작할 수 있어, 필요할 때만 모듈을 가져오고 사용할 수 있습니다.
  3. 기능성

    • CommonJS는 npm과 같은 모듈 저장소에서 로드해야 합니다.
      - CommonJS 모듈은 주로 npm과 같은 패키지 관리자를 통해 설치되고 로드됩니다.
    • CommonJS는 Node.js 애플리케이션의 컨텍스트 내에서만 액세스할 수 있습니다(Node.js에서 사용하도록 설계되었기 때문). Browerify와 같은 도구를 사용하면 브라우저에서도 사용할 수 있습니다.

      Node.js 애플리케이션의 컨텍스트? Node.js 애플리케이션의 실행 환경이나 범위를 의미합니다.

  4. 컴파일

    • CommonJS는 모든 Node.js 환경에서 로드할 수 있습니다.
    • ECMAScript Modules는 네이티브로 지원되는 환경에서 더 빠르고 효율적입니다.

      네이티브로 지원되는 환경? 브라우저나 Node.js 같은 최신 자바스크립트 엔진이 ECMAScript Moduels를 직접 지원하는 것을 의미합니다.

  5. 의존성

    • 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 애플리케이션을 구성하는 여러 모듈을 번들링하여 단일 파일로 생성합니다. 이를 통해 모듈 간 의존성을 관리하고 브라우저에서 사용할 수 있는 형식으로 변환합니다.

      모듈 번들러? 여러 개의 모듈을 하나의 번들(묶음)로 만들어주는 도구입니다.

      번들링? 모듈 번들러가 수행하는 작업 중 하나로, 애플리케이션에서 사용하는 모든 모듈을 결합하여 하나의 번들 파일로 생성하는 과정을 말합니다.

🤔 그렇다면, CommonJS와 ECMAScript Modules 중 우리는 어떤 걸 선택해서 사용하면 좋을까?

아래 두 가지 경우에 대해 고려해 볼 수 있습니다:

  • 새 프로젝트를 시작할 때
    새로운 프로젝트를 시작할 때는 ECMAScript Modules를 선택하는 것을 추천합니다. 이 모듈 시스템은 많은 기능이 표준화되어 있어서 새로운 프로젝트에서의 사용을 권장합니다.
  • 기존의 프로젝트를 유지보수할 때
    이미 존재하는 Node.js 프로젝트를 유지 보수하거나 Node.js 12 이전의 버전을 사용하는 경우(ECMAScript Module은 Node.js 12부터 지원됩니다), CommonJS 모듈 시스템을 계속 사용하는 것을 권장합니다.

🤔 참고 자료

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

profile
책을 좋아하는 개발자입니다.

0개의 댓글