Module system with ESM | JavaScript

Bori·2023년 9월 2일
0

어쨌든 공부

목록 보기
29/40

ESM(ECMAScript Module, ES Module)

ESM는 ES6부터 지원하고 있는 JavaScript의 표준 모듈 시스템입니다.

ES6 이전에는 브라우저 환경에서 사용할 수 있는 표준 모델 시스템이 없었습니다.
필요한 파일(모듈)을 생성하여 <script src="script.js"></script> 의 형태로 파일을 직접 불러오는 방법을 사용했습니다.
자바스크립트로 작성된 외부 라이브러리를 사용하기 위해서 공식적으로 배포하는 스크립트 파일을 다운로드한 후 함께 묶어서 배포하거나 CDN으로 제공되는 주소를 이용하는 방법을 주로 사용했습니다.
하지만 <script> 만으로는 복잡한 시스템에서 많은 파일(모듈)들을 효율적으로 관리하기 어렵기 때문에 이를 해결하기 위한 모듈 시스템이 필요했습니다.

CommonJS, AMD 등 여러 모듈 시스템이 등장했지만 JavaScript 자체에서 모듈 시스템을 지원해야한다는 필요성이 높아졌습니다.

그래서 ES6 사양에서 JavaScript의 표준 모듈 시스템이 명세되었고, 이를 ESM(ECMAScript Module, ES Module) 이라고 부릅니다.

사용 방법

현재 모듈에서 다른 모듈을 사용할 때 import, 현재 모듈에서 다른 모듈로 내보낼 때는 export를 사용합니다.

export

export에는 default export(기본 내보내기)와 named export(유명 내보내기)가 있습니다.

  • named export

    export 구문을 통해 내보낼 수 있고, 하나의 모듈 내에서 named export는 여러 개 존재할 수 있습니다. 따라서 여러 값을 내보낼 때 유용합니다.

    // module.js
    const myVariable = 'My variable';
    const myFunction = () => {
      console.log('My Function');
    }
    
    export { myVariable, myFunction };
    // main.js
    import { myVariable, myFunction } from './module.js'
    
    console.log(myVariable);
    myFunction();

    named exportimport 할 때 내보낸 이름과 동일한 이름을 사용해야 하고, 가져올 모듈을 중괄호 안에 작성합니다.

  • default export

    default exportexport default 구문을 통해 내보내기를 하고, 하나의 모듈 내에 하나만 존재할 수 있습니다.
    import 할 때 중괄호 없이 가져올 모듈의 이름을 통해 가져옵니다.
    또한, default export는 내보낸 이름과 다른 이름으로 가져올 수 있습니다.

    // module.js
    const myVariable = 'My variable';
    const myFunction = () => {
      console.log('My Function');
    }
    
    export { myVariable, myFunction };
    // main.js
    import { myVariable, myFunction } from './module.js'
    
    console.log(myVariable);
    myFunction();

export from

export fromimportexport를 한 번에 처리할 수 있는 문법으로 이를 이용하여 가져온 모듈을 다시 내보낼 수 있습니다.
주로 패키지의 다른 모듈들을 한 번에 모아 일관된 형태로 내보내거나 관리하고 싶을 경우 사용합니다.

// 가져와서 내보내기
export myVariable from "myVariable.js";

// import, export를 이용하여 가져와서 내보내기
import myVariable from 'myVariable.js';
export myVariable;

다른 이름으로 import/export 하기

import 또는 export하는 모듈 이름 뒤에 as를 붙여 다른 이름으로 import/export를 할 수 있습니다.

// 다른 이름으로 export 하기
const myVariable = 'My variable';
export { myVariable as variable }; // myVariable를 variable 라는 이름으로 export

// 다른 이름으로 import 하기
import { myVariable as variable } from 'myVariable.js'; // myVariable를 variable 라는 이름으로 import

ESM 특징

동기/비동기 로드를 모두 지원하고 문법이 간단합니다.
그리고 실제 객체/함수를 바인딩하기 때문에 순환 참조 관리가 편합니다.

CommonJS는 require/module.exports를 동적으로 동작할 수 있습니다.
따라서, 빌드타임에 정적 분석을 적용하기 어렵고 런타임에 모듈 관계를 파악할 수 있습니다.

// require
const utilName = /* 동적인 값 */
const util = require(`./utils/${utilName}`);

// module.exports
function foo() {
  if (/* 동적인 조건 */) {
    module.exports = /* ... */;
  }
}
foo();

ESM은 정적 구조를 가지며 모듈끼리 의존하도록 강제합니다. import path에 동적인 값을 사용할 수 없고, export는 항상 최상위 스코프에서만 사용할 수 있습니다.

import util from `./utils/${utilName}.js`; // 불가능

import { add } from "./utils/math.js"; // 가능

function foo() {
  export const value = "foo"; // 불가능
}

export const value = "foo"; // 가능

따라서 ESM은 빌드 단계에서 정적 분석을 통해 모듈 간의 의존 관계를 파악할 수 있고, 트리쉐이킹을 쉽게 할 수 있습니다.

마무리

  • CommonJs, AMD에 이어 ESM에 대한 내용을 작성해보았습니다.
  • 아직 각 모듈 시스템의 동작 방식 그리고 그에 따른 순환참조, 트리쉐이킹에 미치는 영향에 대한 내용이 부족하지만 차근차근 내용을 이어 붙여보도록 하겠습니다.

참고

0개의 댓글