일반적으로 export, import문을 사용하는 것은 정적인 방식이다.
정적인 import 방식은 문법이 단순하고 제약사항이 존재한다.
모듈 경로엔 원시 문자열만 들어갈 수 있기 때문에, 함수 호출 결과값을 경로로 쓰는 것이 불가능했다.
import ... from getModuleName();
모듈 경로는 문자열만 허용되기 때문에 에러가 발생한다.
if(...) { import ...; }
모듈을 조건부로 불러올 수 없으므로 에러가 발생한다.
{ import ...; }
import문은 블록 안에 올 수 없으므로 에러가 발생한다.
이런 제약사항이 만들어진 이유는 import/export느 코드 구조의 중심을 잡아주는 역할을 하기 때문이다.
코드 구조를 분석해 모듈을 한데 모아 번들링하고, 사용하지 않는 모듈은 제거해야 하는데 코드 구조가 간단하고 고정되어 있을 때만 이런 작업이 가능하다.
import(module) 표현식은 모듈을 읽고 내보내는 모든 것을 포함하는 객체를 담고 있는 Promise를 반환한다.
어디서나 호출 가능하고, 코드 내 어디서든 동적으로 사용할 수도 있다.
let modulePath = prompt("어떤 모듈을 불러오고 싶으세요?");
import(modulePath)
.then(obj => <모듈 객체>)
.catch(err => <로딩에러>)
async 함수 안에서 let module = await import(modulePath)
와 같이 사용하는 것도 가능하다.
// say.js
export function hi() {
alert('안녕하세요');
}
export function bye() {
alert('안녕히 가세요');
}
// index.js
let {hi, bye} = await import('./say.js')
hi();
bye();
// say.js
export default function () {
alert("export default한 모듈을 불러왔습니다!");
}
let obj = await import('./say.js');
let say = obj.default;
// let {default: say} = await import('./say.js') 로 표현 가능
say();
⭐️ import( )는 함수 호출이 아니라 괄호를 쓰는 특별한 문법 중 하나이다.
따라서 import를 변수에 복사하거나 call/apply를 사용하는 것은 불가능하다.
⭐️ dynamic import는 일반 스크립트에서도 동작한다.
따라서 script type="module"이 없어도 된다.