: 코드의 가장 상위에서 모듈을 불러오는 것
: 코드 실행 중에 모듈을 동적으로 불러오는 것
동적 가져오기를 사용하면 애플리케이션에 필요한 모듈을 필요한 시점에 로드할 수 있으므로, 대규모 애플리케이션에서 초기 로드 속도를 향상시키고 필요하지 않은 모듈의 로드를 지연시킬 수 있다.
동적 가져오기를 하려면import()
함수를 사용하면 된다.
import()
import()
함수는 모듈을 읽고 이 모듈이 export하는 것들을 모두 포함하는 객체를 담은 이행된(fulfilled) 프로미스를 반환한다.
then()
메소드를 사용해 모듈 로드 후에 수행할 작업을 정의할 수 있으며, catch()
메소드로 모듈 로드 중에 발생하는 오류를 처리할 수도 있다.import('./module.js')
.then((module) => console.log(module))
.catch((err) => console.log(err));
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}`);
}
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' 출력
사용자 정보를 확인하여 관리자일 경우 관리자 모드(편집 모드)를 키는 함수를 호출하려고 한다.
// 정적 가져오기
import { setupAdminUser } from './admin.js';
if (user.admin) {
setupAdminUser();
}
정적 가져오기를 사용하면, 실제로는 관리자만 해당 코드를 실행하지만 일반 사용자들도 setupAdminUser
함수를 다운로드하게 된다. 이는 admin.js
파일이 거대한 파일일 경우, 사용자들은 이 코드를 필요로 하지 않음에도 다운로드하게 되고 이는 페이지 로드 속도를 저하시킬 수 있다.
이 코드를 동적 가져오기로 고쳐보면 아래처럼 수정할 수 있다.
이렇게 하면 사용자 정보를 확인하여 관리자인 경우에만 admin.js
파일을 다운로드하게 된다.
// 동적 가져오기
if (user.admin) {
import('./admin.js').then({ setupAdminUser }) => {
setupAdminUser();
}
}
이렇게 동적 가져오기를 사용하면 관리자 기능에 필요한 파일과 코드는 관리자에게만 제공되며, 일반 사용자들은 해당 파일을 다운로드하지 않아도 된다.
그리고 사용자들은 불필요한 리소스 다운로드를 하지 않아도 되기에 초기 로드 속도를 향상시킬 수 있다.
import()
함수 안에 템플릿 리터럴을 이용해 변수를 사용할 수도 있다.
en-translations.js
, fr-translations.js
파일도 인사말만 hi, salut 이고 동일하게 작성되어있다.
const translations = {
HI: "hola"
};
export default translations;
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가 출력된다.
})
반복문 안에서도 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
구문과 함께 사용할 수도 있다. 👍
const shapes = [
{type: 'rectangle'}
{type: 'triangle'}
{type: 'rectangle'}
];
shapes.forEach(async (shape) => {
const { default: render } = await import(`./${shape.type}.js`)
render(shape);
})
Import할때 스트링 값을 변수로 남겨주는게 인상적이네요. Render라는 메소드가 있나봐요! 저도 나중에 써봐야겠네요 ㅎㅎ