[JavaScript] 동적 모듈 가져오기

import() 표현식의 기본 개념

정적 import 문을 사용하는 기존의 정적 가져오기와 달리 동적 가져오기는 import() 표현식을 활용하여 런타임에 모듈을 비동기적으로 로드합니다. 이 표현식은 함수 호출과 유사한 문법을 가지지만, 실제 함수 호출이 아니라 특별한 문법입니다.

import(moduleSpecifier)는 모듈을 로드하고, 모듈의 모든 내보내진 기능이 담긴 객체를 반환하는 프라미스를 생성합니다.

// math.js
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

export default function multiply(a, b) {
  return a * b;
}

이제 main.js라는 다른 모듈에서 math.js 모듈을 동적으로 로드하고 내보낸 기능을 활용해 보겠습니다.

// main.js
async function loadMathModule() {
  try {
    // math.js 모듈을 동적으로 로드합니다.
    const mathModule = await import('./math.js');

    // 이름이 지정된 내보내기는 구조 분해 할당을 통해 액세스합니다.
    const { add, subtract } = mathModule;

    // 기본 내보내기는 모듈 객체의 default 속성을 통해 액세스합니다.
    const multiply = mathModule.default;

    console.log("2 + 3 =", add(2, 3));        // 5
    console.log("7 - 4 =", subtract(7, 4));     // 3
    console.log("3 * 4 =", multiply(3, 4));     // 12
  } catch (error) {
    console.error("모듈 로드 실패:", error);
  }
}

document.getElementById('loadButton').addEventListener('click', loadMathModule);
  • 동적 import의 반환값
    • import('./math.js')는 프라미스를 반환하며, 모듈이 성공적으로 로드되면 내보낸 모든 기능이 포함된 객체를 resolve합니다.
  • async/await 사용
    • await를 사용하여 프라미스가 해결될 때까지 기다린 후, 모듈 객체에 접근할 수 있습니다.
  • default와 named export
    • default export는 모듈객체.default로, named export는 객체 구조 분해 할당을 통해 가져올 수 있습니다.

동적 import의 특징

조건부 기능 로드

동적 import는 조건문이나 함수 내부 어디서나 사용할 수 있습니다. 예를 들어, 사용자의 선택에 따라 모듈을 로드할 수 있습니다.

if (userWantsExtraFeatures) {
  import('./extraFeatures.js')
    .then(module => module.init())
    .catch(err => console.error("기능 모듈 로드 실패:", err));
}

비동기적으로 실행

import()는 항상 프라미스를 반환하므로, 모듈 로딩이 완료되기 전까지 후속 작업은 대기됩니다.

async function loadModuleDynamically() {
  try {
    const module = await import('./myModule.js'); // 모듈을 비동기적으로 로드합니다.
    // 로드된 모듈로 작업합니다.
  } catch (error) {
    // 모듈 로드 오류를 처리합니다.
    console.error("모듈 로드 실패:", error);
  }
}

함수 호출이 아님

동적 가져오기는 함수 호출처럼 보일 수 있지만 import() 표현식은 일반 함수가 아니라 JavaScript 구문의 특별한 구문입니다. 동적 import는 일반 함수가 아니므로, 이를 변수에 할당하거나 call/apply 같은 메서드를 사용할 수 없습니다.

const dynamicImport = import('./myModule.js'); // 유효함, 프라미스를 변수에 할당합니다.

import('./myModule.js').then(module => { }); // 유효함, 프라미스 콜백을 사용합니다.

const importFn = import;
importFn('./myModule.js'); // 유효하지 않음, import가 함수가 아닙니다.

프로토콜 제약

브라우저 환경에서 동적 모듈 가져오기에는 JavaScript 모듈이 HTTP/HTTPS 프로토콜을 통해 제공되어야 한다는 프로토콜 제약이 있습니다. file:// 프로토콜을 사용하여 로컬 파일 시스템에서 직접 모듈을 로드하는 것은 도메인 간 보안 제한으로 인해 오류가 발생하거나 예상대로 작동하지 않을 수 있습니다. 모듈이 브라우저에서 올바르게 작동하도록 하려면 로컬 웹 서버 또는 HTTPS를 통해 제공해야 합니다.