Pernyataan ekspor dan impor yang kita bahas di bab sebelumnya disebut “statis”. Sintaksnya sangat sederhana dan bersifat strict.
Pertama, kita tidak bisa membuat parameter import
secara dinamis.
Jalur modul harus berupa string, tidak boleh berupa function panggilan. Berikut contoh yang tidak akan berhasil:
import ... from getModuleName(); // Error, hanya "string" yang diperbolehkan
Kedua, kita tidak bisa meng-impor secara kondisional atau pada saat run-time:
if(...) {
import ...; // Error, tidak diperbolehkan!
}
{
import ...; // Error, kita tidak bisa meng-impor di dalam block-scope
}
Itu karena import
/export
bertujuan untuk menyediakan tulang punggung untuk struktur kode. Itu hal yang baik, karena struktur kode dapat dianalisa, modul dapat dikumpulkan dan digabungkan menjadi satu file dengan alat khusus, ekspor yang tidak digunakan dapat dihapus (“tree-shaken”). Itu memungkinkan hanya karena struktur dari impor/ekspor sederhana dan tetap.
Tetapi bagaimana kita bisa meng-impor modul secara dinamis, sesuai permintaan?
Ekspresi import()
Ekspresi import(modul)
memuat modul dan mengembalikan sebuah promise yang diselesaikan menjadi objek modul yang berisi semua ekspornya. Itu dapat dipanggil dari mana saja dalam kode.
Kita bisa menggunakannya secara dinamis di sembarang tempat kode, misalnya:
let modulePath = prompt("Modul mana yang ingin dimuat?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
Atau, kita bisa menggunakan let module = await import(modulePath)
jika di dalam async function.
Misalnya, jika kita memiliki modul berikut say.js
:
// 📁 say.js
export function hi() {
alert(`Halo`);
}
export function bye() {
alert(`Selamat tinggal`);
}
…Kemudian impor dinamisnya bisa seperti ini:
let { hi, bye } = await import("./say.js");
hi();
bye();
Atau, kalau say.js
mempunyai ekspor default:
// 📁 say.js
export default function () {
alert("Modul dimuat (ekspor default)!");
}
…Kemudian, untuk mengaksesnya, kita bisa menggunakan properti default
dari objek modul:
let obj = await import("./say.js");
let say = obj.default;
// jika dalam satu baris: let {default: say} = await import('./say.js');
say();
Berikut contoh lengkapnya:
export function hi() {
alert(`Halo`);
}
export function bye() {
alert(`Selamat tinggal`);
}
export default function () {
alert("Modul dimuat (ekspor default)!");
}
<!DOCTYPE html>
<script>
async function load() {
let say = await import("./say.js");
say.hi(); // Halo
say.bye(); // Selamat tinggal
say.default(); // Modul dimuat (ekspor default)!
}
</script>
<button onclick="load()">Klik aku</button>
Impor dinamis berfungsi dalam skrip biasa, mereka tidak memerlukan script type="module"
.
Meskipun import()
terlihat seperti pemanggilan sebuah function, akan tetapi itu adalah sintaks khusus yang kebetulan menggunakan tanda kurung (mirip dengan super()
).
Jadi, kita tidak bisa menyalin import
ke dalam variabel atau menggunakan call/apply
dengannya. import
bukan sebuah function.