Dynamické importy

Výkazy exportu a importu, které jsme probrali v předchozích kapitolách, se nazývají „statické“. Syntaxe je velmi jednoduchá a přísná.

Za prvé, nemůžeme dynamicky generovat žádné parametry import .

Cesta modulu musí být primitivní řetězec, nemůže to být volání funkce. Toto nebude fungovat:

import ... from getModuleName(); // Error, only from "string" is allowed

Za druhé, nemůžeme importovat podmíněně nebo za běhu:

if(...) {
 import ...; // Error, not allowed!
}

{
 import ...; // Error, we can't put import in any block
}

To proto, že import /export Cílem je poskytnout páteř pro strukturu kódu. To je dobrá věc, protože strukturu kódu lze analyzovat, moduly lze shromáždit a seskupit do jednoho souboru pomocí speciálních nástrojů, nepoužívané exporty lze odstranit („stromově otřesené“). To je možné pouze proto, že struktura importů/exportů je jednoduchá a pevná.

Jak ale můžeme modul importovat dynamicky, na vyžádání?

Výraz import()

import(module) výraz načte modul a vrátí příslib, který se převede na objekt modulu, který obsahuje všechny jeho exporty. Lze jej volat z libovolného místa v kódu.

Můžeme jej použít dynamicky na libovolném místě kódu, například:

let modulePath = prompt("Which module to load?");

import(modulePath)
 .then(obj => <module object>)
 .catch(err => <loading error, e.g. if no such module>)

Nebo bychom mohli použít let module = await import(modulePath) pokud je součástí asynchronní funkce.

Například, pokud máme následující modul say.js :

// 📁 say.js
export function hi() {
 alert(`Hello`);
}

export function bye() {
 alert(`Bye`);
}

…Pak dynamický import může vypadat takto:

let {hi, bye} = await import('./say.js');

hi();
bye();

Nebo, pokud say.js má výchozí export:

// 📁 say.js
export default function() {
 alert("Module loaded (export default)!");
}

…Poté, abychom k němu měli přístup, můžeme použít default vlastnost objektu modulu:

let obj = await import('./say.js');
let say = obj.default;
// or, in one line: let {default: say} = await import('./say.js');

say();

Zde je úplný příklad:

Resultsay.jsindex.html
export function hi() {
 alert(`Hello`);
}

export function bye() {
 alert(`Bye`);
}

export default function() {
 alert("Module loaded (export default)!");
}
<!doctype html>
<script>
 async function load() {
 let say = await import('./say.js');
 say.hi(); // Hello!
 say.bye(); // Bye!
 say.default(); // Module loaded (export default)!
 }
</script>
<button onclick="load()">Click me</button>
Poznámka:

Dynamické importy fungují v běžných skriptech, nevyžadují script type="module" .

Poznámka:

Ačkoli import() vypadá jako volání funkce, je to speciální syntaxe, která náhodou používá závorky (podobně jako super() ).

Nemůžeme tedy zkopírovat import na proměnnou nebo použijte call/apply s tím. Není to funkce.