동적 불러오기 (Dynamic import)

지은·2023년 6월 23일
0

JavaScript

목록 보기
41/42

정적 불러오기 (Static import)

: 코드의 가장 상위에서 모듈을 불러오는 것

동적 불러오기 (Dynamic import)

: 코드 실행 중에 모듈을 동적으로 불러오는 것

동적 가져오기를 사용하면 애플리케이션에 필요한 모듈을 필요한 시점에 로드할 수 있으므로, 대규모 애플리케이션에서 초기 로드 속도를 향상시키고 필요하지 않은 모듈의 로드를 지연시킬 수 있다.

동적 가져오기를 하려면import() 함수를 사용하면 된다.

import()

import() 함수는 모듈을 읽고 이 모듈이 export하는 것들을 모두 포함하는 객체를 담은 이행된(fulfilled) 프로미스를 반환한다.

  • then() 메소드를 사용해 모듈 로드 후에 수행할 작업을 정의할 수 있으며,
  • catch() 메소드로 모듈 로드 중에 발생하는 오류를 처리할 수도 있다.
import('./module.js')
  .then((module) => console.log(module))
  .catch((err) => console.log(err));

예제 1

user.js

User 클래스와 printUser 함수를 export 하고 있는 user.js 모듈

export default class User {
  constructor(first, last) {
    this.first = first;
    this.last = last;
  }
}

export function printUser(user) {
  console.log(`${user.first} ${user.last}`);
}

script.js

import("./user.js")
  .then((module) => console.log(module)); // {default: ƒ User(), printUser: ƒ printUser()}

모듈을 콘솔에 출력해보면 다음과 같은 형태로 모듈이 받아와지는 걸 확인할 수 있다.
{default: ƒ User(), printUser: ƒ printUser()}

여기에 구조분해할당으로 받아와 User 클래스와 printUser 함수를 사용할 수 있다.
setTimeout() 함수 안에 이 import 표현식을 넣으면 5초 후에 모듈을 불러오고 콘솔에 'JIEUN CHUN'이 출력되는 것을 확인할 수 있다.

// 정적 가져오기
import User, { printUser } from "./user.js";

const instance = new User("Jieun", "Chun");

printUser(instance); // 'Jieun Chun'


// 동적 가져오기
setTimeout(() => {
  import("./user.js").then(({ default: User, printUser }) => {
    const instance = new User("JIEUN", "CHUN");

    printUser(instance);
  });
}, 5000); // 5초 후 'JIEUN CHUN' 출력

예제 2

사용자 정보를 확인하여 관리자일 경우 관리자 모드(편집 모드)를 키는 함수를 호출하려고 한다.

// 정적 가져오기
import { setupAdminUser } from './admin.js';

if (user.admin) {
  setupAdminUser();
}

정적 가져오기를 사용하면, 실제로는 관리자만 해당 코드를 실행하지만 일반 사용자들도 setupAdminUser 함수를 다운로드하게 된다. 이는 admin.js 파일이 거대한 파일일 경우, 사용자들은 이 코드를 필요로 하지 않음에도 다운로드하게 되고 이는 페이지 로드 속도를 저하시킬 수 있다.

이 코드를 동적 가져오기로 고쳐보면 아래처럼 수정할 수 있다.
이렇게 하면 사용자 정보를 확인하여 관리자인 경우에만 admin.js 파일을 다운로드하게 된다.

// 동적 가져오기
if (user.admin) {
  import('./admin.js').then({ setupAdminUser }) => {
    setupAdminUser();
  }
}

이렇게 동적 가져오기를 사용하면 관리자 기능에 필요한 파일과 코드는 관리자에게만 제공되며, 일반 사용자들은 해당 파일을 다운로드하지 않아도 된다.
그리고 사용자들은 불필요한 리소스 다운로드를 하지 않아도 되기에 초기 로드 속도를 향상시킬 수 있다.


변수 사용

import() 함수 안에 템플릿 리터럴을 이용해 변수를 사용할 수도 있다.

예제 1

정적 가져오기

sp-translations.js

en-translations.js, fr-translations.js 파일도 인사말만 hi, salut 이고 동일하게 작성되어있다.

const translations = {
  HI: "hola"
};

export default translations;

script.js

import englishTranslations from "./en-translations";
import spanishTranslations from "./sp-translations";
import frenchTranslations from "./fr-translations"; // 사용하지 않는 대용량의 파일을 import한다.

const user = { locale: "sp" };

let translations;

switch (user.locale) {
  case "sp":
    translations = spanishTranslations;
    break;
  case "fr":
    translations = frenchTranslations;
    break;
  default:
    translations = englishTranslations; // user.locale이 sp이나 fr이 아닌 나머지의 경우 기본적으로 영어 번역이 적용된다.
}

console.log(translations.HI); // hola

동적 가져오기

import할 파일의 이름을 템플릿 리터럴을 사용해 동적으로 생성할 수 있다.

const user = { locale: "sp" };

import(`./${user.locale}-translations.js`) // './sp-translations.js'
  .then(({ default: translations }) => {
    console.log(translations.HI); // hola
  })

만약 user.locale에 "ko"와 같이 다운로드할 파일이 없는 경로를 입력했을 경우 기본값으로 englishTranlations를 불러오게 하고 싶다면, then() 메소드 이전에 catch()를 사용해 에러 처리를 해주면 된다.

const user = { locale: "ko" };

import(`./${user.locale}-translations.js`)
  .catch(() => import('./en-translations.js')) // 위의 import문에서 에러가 날 경우, catch 구문이 실행되며 영어 번역을 불러온다.
  .then(({ default: translations }) => {
    console.log(translations.HI); // catch문의 import가 정상적으로 이루어지면 이어서 then이 실행되며 hi가 출력된다.
  })

예제 2

반복문 안에서도 import() 함수를 사용할 수 있다.

정적 가져오기

import renderRectangle from './rectangle.js';
import renderTriangle from './triangle.js';

const shapes = [
  {type: 'rectangle'}
  {type: 'triangle'}
  {type: 'rectangle'}
];

shapes.forEach((shape) => {
  switch (shape.type) {
    case: 'rectangle':
      renderRectangle(shape);
      break;
    case: 'triangle':
      renderTriangle(shape);
      break;
  }
})

동적 가져오기

위의 코드를 동적 가져오기로 수정해보면, forEach 구문 안에서도 도형을 렌더링하는데 필요한 함수를 import하도록 할 수 있다.

const shapes = [
  {type: 'rectangle'}
  {type: 'triangle'}
  {type: 'rectangle'}
];

shapes.forEach((shape) => {
  import(`./${shape.type}.js`).then(({ default: render }) => render(shape));
})

async / await와 함께 사용하기

async/await 구문과 함께 사용할 수도 있다. 👍

const shapes = [
  {type: 'rectangle'}
  {type: 'triangle'}
  {type: 'rectangle'}
];

shapes.forEach(async (shape) => {
  const { default: render } = await import(`./${shape.type}.js`)
  render(shape);
})
profile
개발 공부 기록 블로그

5개의 댓글

comment-user-thumbnail
2023년 6월 24일

Import할때 스트링 값을 변수로 남겨주는게 인상적이네요. Render라는 메소드가 있나봐요! 저도 나중에 써봐야겠네요 ㅎㅎ

1개의 답글
comment-user-thumbnail
2023년 6월 25일

동적 불러오기를 이용하면 불필요한 렌더링을 확실히 줄일 수 있겠어요! 잘 보고 갑니당

답글 달기
comment-user-thumbnail
2023년 6월 25일

항상 최상단에 정적으로 가져와야 하는 줄 알았는데 !! 잘 배우고 갑니다 !!

답글 달기
comment-user-thumbnail
2023년 6월 25일

딥하게는 모르고 있었는데 기억해둬야겠어용 ㅎㅎ

답글 달기