JavaScript
Modules

모듈에 대해 설명해주세요

모듈은 단지 파일 하나에 불과하며 스크립트 하나는 모듈 하나이다.

모듈은 코드의 논리적인 조각이다.

  • export 지시자를 변수나 함수 앞에 붙이면 외부 모듈에서 해당 변수나 함수에 접근 가능
  • import 지시자를 사용하면 외부 모듈의 기능을 가져오기 가능

모듈은 특수한 키워드나 기능과 함께 사용되므로 <script type="module"> 같은 속성을 설정해 해당 스크립트가 모듈이란 것을 브라우저에게 알려줘야 한다.

모듈은 로컬 파일에서 동작하지 않고 HTTP, HTTPS 프로토콜을 통해서만 동작한다.

모듈 기능

엄격 모드

모듈은 항상 엄격 모드(use strict)로 실행된다. 선언되지 않은 변수에 값을 할당하는 등의 코드는 에러를 발생시킨다.

<script type="module">
  a = 5; // 에러
</script>

모듈 레벨 스코프

모듈은 자신만의 스코프가 있다.

모듈 내부에서 정의한 변수나 함수는 다른 스크립트에서 접근할 수 없다.

외부에 공개하려는 모듈은 export, 내보내진 모듈을 가져와 사용하려면 import 해야 한다.

단 한 번의 평가

동일한 모듈이 여러 곳에서 사용되어도 모듈은 최초 호출 시 단 한 번만 실행된다.

// 📁 admin.js
export let admin = {
  name: "John",
};
// 📁 1.js
import { admin } from "./admin.js";
admin.name = "Pete";
 
// 📁 2.js
import { admin } from "./admin.js";
alert(admin.name); // Pete

1.js2.js 모두 같은 객체를 가져와서 1.js에서 객체에 가한 조작을 2.js에서도 확인할 수 있다.

import.meta

import.meta 객체는 현재 모듈에 대한 정보를 제공한다.

this는 undefined

모듈 최상위 레벨의 thisundefined이다. 모듈이 아닌 일반 스크립트의 this는 전역 객체인 것과 대조된다.

<script>
  alert(this); // window
</script>
 
<script type="module">
  alert(this); // undefined
</script>

브라우저 특정 기능

브라우저 환경에서 type="module"이 붙은 스크립트가 일반 스크립트와 어떤 점이 다른지 알아본다.

지연 실행

모듈 스크립트는 항상 지연 실행된다. 마치 defer 속성을 붙인 것처럼 실행된다.

모듈 스크립트는 다음과 같은 특징을 가진다.

  • 외부 모듈 스크립트 <script type="module" src="...">를 다운로드할 때 브라우저의 HTML 처리가 멈추지 않는다. 브라우저는 외부 모듈 스크립트와 기타 리소스를 병렬적으로 불러온다.
  • 모듈 스크립트는 HTML 문서가 완전히 준비될 때까지 대기 상태에 있다가 HTML 문서가 완전히 만들어진 이후 실행된다.
  • 스크립트의 상대적 순서가 유지된다.
<script type="module">
  alert(typeof button);
  // 모듈 스크립트는 지연 실행되기 때문에 페이지가 모두 로드되고 난 다음에 alert 함수가 실행
  // object가 정상적으로 출력
</script>
 
<script>
  alert(typeof button);
  // 일반 스크립트는 페이지가 완전히 구성되기 전이라도 바로 실행
  // 버튼 요소가 페이지에 만들어지기 전에 접근하였기 때문에 undefined가 출력
</script>
 
<button id="button">Button</button>

인라인 스크립트의 비동기 처리

모듈이 아닌 일반 스크립트에서 async 속성은 외부 스크립트를 불러올 때만 유효하다. async 속성이 붙은 스크립트는 로딩이 끝나면 다른 스크립트나 HTML 문서가 처리되길 기다리지 않고 바로 실행된다.

반면 모듈 스크립트에선 async 속성을 인라인 스크립트에도 적용할 수 있다.

인라인 스크립트에 async 속성이 붙으면 다른 스크립트나 HTML이 처리되길 기다리지 않고 바로 실행된다. 광고나 문서 레벨 이벤트 리스너, 카운터 같이 어디에도 종속되지 않는 기능을 구현할 때 유용하게 사용할 수 있다.

<script async type="module">
  import { counter } from "./analytics.js";
 
  counter.count();
</script>

외부 스크립트

  1. src값이 동일한 외부 스크립트는 한 번만 실행된다.
  2. 외부 사이트같이 다른 오리진에서 모듈 스크립트를 불러오려면 CORS 챕터에서 설명한 바와 같이 CORS 헤더가 필요하다.

경로가 없는 모듈은 금지

import { sayHi } from "sayHi"; // Error!
// './sayHi.js'와 같이 경로 정보를 지정해 주어야 합니다.

호환을 위한 nomodule

브라우저

<script type="module">
  alert("모던 브라우저를 사용하고 계시군요.");
</script>
 
<script nomodule>
  alert(
    "type=module을 해석할 수 있는 브라우저는 nomodule 타입의 스크립트는 넘어갑니다. 따라서 이 alert 문은 실행되지 않습니다."
  );
  alert(
    "오래된 브라우저를 사용하고 있다면 type=module이 붙은 스크립트는 무시됩니다. 대신 이 alert 문이 실행됩니다."
  );
</script>

빌드 도구

웹팩과 같은 번들 도구를 활용하여 성능을 개선한다.

GPT로 문장 정리하기

모듈에 대해 설명해줘

  • 코드의 논리적인 조각
  • 코드의 재사용, 유지보수, 네임스페이스 관리 등을 위해 사용
  • 주요 특징
    • 네임스페이스 제공
      • 자체적인 스코프 제공하여 변수, 함수, 클래스 등의 식별자 충돌 방지
    • 코드 재사용
      • 코드를 논리적으로 그룹화하여 코드의 재사용성 증가
    • 캡슐화
      • 내부 구현을 숨기고 외부에 필요한 인터페이스만 노출하여 캡슐화 제공
    • 독립성
      • 독립적으로 개발, 테스트, 유지보수할 수 있는 단위로 구성
    • 의존성 관리
      • 다른 모듈에 의존 가능

키워드 정리

  • CommonJS
  • ES Modules

참고 자료