前の章で説明した`export`文と`import`文は、「静的」と呼ばれます。構文は非常にシンプルで厳格です。
まず、`import`のパラメータを動的に生成することはできません。
モジュールパスはプリミティブ文字列でなければならず、関数呼び出しにすることはできません。これは動作しません。
import ... from getModuleName(); // Error, only from "string" is allowed
次に、条件付きまたは実行時にインポートすることはできません。
if(...) {
import ...; // Error, not allowed!
}
{
import ...; // Error, we can't put import in any block
}
これは、`import`/`export`がコード構造のバックボーンを提供することを目的としているためです。コード構造を分析し、モジュールを収集して特別なツールで1つのファイルにバンドルし、未使用のエクスポートを削除(「ツリーシェイキング」)できるため、これは良いことです。これは、インポート/エクスポートの構造がシンプルで固定されているためだけに可能です。
しかし、モジュールを動的に、オンデマンドでインポートするにはどうすればよいでしょうか?
import()式
`import(module)`式はモジュールを読み込み、すべてのエクスポートを含むモジュールオブジェクトに解決されるPromiseを返します。コード内の任意の場所から呼び出すことができます。
たとえば、コード内の任意の場所で動的に使用できます。
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
または、`async`関数内であれば、`let module = await import(modulePath)`を使用できます。
たとえば、次のようなモジュール`say.js`があるとします。
// 📁 say.js
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
…すると、動的インポートは次のようになります。
let {hi, bye} = await import('./say.js');
hi();
bye();
または、`say.js`にデフォルトのエクスポートがある場合
// 📁 say.js
export default function() {
alert("Module loaded (export default)!");
}
…すると、それにアクセスするために、モジュールオブジェクトの`default`プロパティを使用できます。
let obj = await import('./say.js');
let say = obj.default;
// or, in one line: let {default: say} = await import('./say.js');
say();
完全な例を以下に示します。
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>
動的インポートは通常のスクリプトで機能し、`script type="module"`は必要ありません。
`import()`は関数呼び出しのように見えますが、たまたま括弧を使用する特別な構文です(`super()`に似ています)。
そのため、`import`を変数にコピーしたり、`call/apply`で使用したりすることはできません。関数ではありません。
コメント