2 Oktober 2020

Impor dinamis

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:

Hasil
say.js
index.html
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>
Tolong dicatat:

Impor dinamis berfungsi dalam skrip biasa, mereka tidak memerlukan script type="module".

Tolong dicatat:

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.

Peta tutorial