import()
========

**`import()`** 構文は、よくダイナミックインポートと呼ばれますが、非同期かつ動的に、 ECMAScript モジュールを、潜在的にモジュールではない環境に読み込めるようにする関数風の式です。

宣言スタイルのものとは異なり、動的インポートは必要なときだけ評価され、より柔軟な構文が可能になります。

構文
--


```js
import(moduleName)
```


`import()` 呼び出しは関数呼び出しによく似た構文ですが、 `import` 自体はキーワードであり、関数ではありません。`const myImport = import` のようなエイリアスを作成することはできず、 `SyntaxError` が発生します。

### 引数

`moduleName`

インポート元モジュール。指定子の評価はホスト次第ですが、常に静的なインポート宣言と同じアルゴリズムに従います。

### 返値

モジュール名前空間オブジェクト、すなわち `moduleName` からのすべてのエクスポートを格納したオブジェクトで履行されるプロミスを返します。

`import()` の評価で同期的にエラーが発生することはありません。`moduleName` は文字列に強制されるので、強制が発生した場合、そのエラーとともにプロミスが拒否されます。

解説
--

import宣言の構文（`import something from "somewhere"`）は静的で、常にモジュールが 読み込まれた時点で評価される結果となります。ダイナミックインポートを使用すると、import宣言の構文の硬直性を回避し、条件付きまたはオンデマンドでモジュールを読み込むことができます。以下のような理由で、動的インポートが使用することがあります。

* 静的にインポートするとコードの読み込みが著しく遅くなる場合で、インポートしているコードが必要になる可能性が低い、または後日必要になる可能性がある場合。
* 静的にインポートすると、プログラムのメモリー使用量が大幅に増える場合で、インポートするコードが必要になる可能性が低い場合。
* 読み込むモジュールが読み込む時点で存在しない場合。
* インポート指定子文字列を動的に構築する必要がある場合。（静的インポートでは静的指定のみ対応しています。）
* インポートされるモジュールに副作用があり、ある条件を満たさない限りその副作用を望まない場合。 （モジュールに副作用を持たないことを推奨しますが、モジュールの依存関係でこれを制御できないこともあります）。
* モジュール以外の環境（例: `eval` やスクリプトファイル）にいるとき。

動的インポートは必要なときだけ使用してください。静的な形は、初期の依存関係を読み込むのに適しており、静的解析ツールやツリーシェイキングの恩恵を受けやすくなります。

ファイルがモジュールとして実行されていない場合（HTML ファイルで参照される場合、script タグに `type="module"` が必要）、静的な import 宣言は使用できませんが、非同期の動的 import 構文は常に利用できるので、モジュール以外の環境にもモジュールをインポートすることができます。

### モジュール名前空間オブジェクト

*モジュール名前空間オブジェクト* は、モジュールからのすべてのエクスポートを記述しているオブジェクトです。これは静的なオブジェクトで、モジュールが評価されるときに作成されます。モジュールの名前空間オブジェクトにアクセスする方法は 2 つあります。名前空間インポート (`import * as name from moduleName`)、または動的インポートの履行値を通じてです。

モジュール名前空間オブジェクトは封印された、プロトタイプが `null`のオブジェクトです。これは、オブジェクトのすべての文字列キーが、モジュールのエクスポートに対応し、余分なキーがないことを意味しています。すべてのキーは辞書順に列挙可能で（すなわち`Array.prototype.sort()` の既定の動作）、デフォルトエクスポートは `default` というキーで利用できます。さらに、モジュール名前空間オブジェクトには `@@toStringTag` プロパティがあり、値は `"Module"` で、 `Object.prototype.toString()` で使用されるものです。

文字列プロパティは構成不可能で、`Object.getOwnPropertyDescriptors()` を使用してその記述子を取得すると書き込みが可能になります。しかし、プロパティを新しい値に割り当てることはできないため、実質的に読み取り専用となります。この動作は、静的インポートが「ライブ結合」- 値をエクスポートするモジュールは再割り当てることができるが、インポートするモジュールはできない - を作成するという事実を反映したものです。構成不可、書き込み不可のプロパティは一定でなければならないため、プロパティの書き込み可否は、値が変化する可能性を反映します。例えば、変数のエクスポートされた値を再代入することができ、新しい値はモジュール名前空間オブジェクトで監視することができます。

それぞれのモジュール指定子は固有のモジュール名前空間オブジェクトに対応するため、一般的には以下のようになります。


```js
import \* as mod from "/my-module.js";

import("/my-module.js").then((mod2) => {
  console.log(mod === mod2); // true
});
```


ただし、1つだけ奇妙な場合があります。プロミスは決して thenable に履行されることはないので、もし `my-module.js` モジュールが `then()` という関数をエクスポートすると、その関数はダイナミックインポートのプロミスが履行されると自動的に呼ばれることになります。


```js
// my-module.js
export function then() {
  console.log("then() called");
}
```



```js
// main.js
import \* as mod from "/my-module.js";

import("/my-module.js").then((mod2) => {
  // Logs "then() called"
  console.log(mod === mod2); // false
});
```

例
-

### 副作用のあるモジュールだけをインポート


```js
(async () => {
  if (somethingIsTrue) {
    // 副作用のあるモジュールをインポート
    await import("/modules/my-module.js");
  }
})();
```


自分のプロジェクトで ESM をエクスポートするパッケージを使用する場合、副作用がある場合のみインポートすることもできます。この場合、パッケージのエントリーポイントファイル（およびこのファイルがインポートするすべてのファイル）内のコードのみが実行されます。

### デフォルトをインポート

返されたオブジェクトから "default" のキーを再構築し、名前を変更する必要があります。


```js
(async () => {
  if (somethingIsTrue) {
    const {
      default: myDefault,
      foo,
      bar,
    } = await import("/modules/my-module.js");
  }
})();
```

### ユーザー操作に応じたオンデマンドのインポート

この例では、ユーザーの操作（この場合はボタンのクリック）に基づいてページに機能を読み込ませ、そのモジュール内の関数を呼び出す方法を示しています。この機能を実装するための唯一の方法というわけではありません。`import()` 関数は `await` にも対応しています。


```js
const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
  link.addEventListener("click", (e) => {
    e.preventDefault();

    import("/modules/my-module.js")
      .then((module) => {
        module.loadPageInto(main);
      })
      .catch((err) => {
        main.textContent = err.message;
      });
  });
}
```

### 環境に応じて様々な形のモジュールをインポート

サーバーサイドレンダリングなどの処理では、サーバーとブラウザーで異なるグローバルやモジュールと対話するため、異なるロジックを読み込む必要がある場合があります（例えば、ブラウザーのコードは `document` や `navigator` などのウェブ API に、サーバーコードはサーバーファイルシステムにアクセスすることができます）。条件付きの動的インポートによって、このようなことが可能になります。


```js
let myModule;

if (typeof window === "undefined") {
  myModule = await import("module-used-on-server");
} else {
  myModule = await import("module-used-in-browser");
}
```

### リテラルでない指定子を持つモジュールのインポート

動的インポートでは、モジュール指定子として、文字列リテラルに限らず、任意の式で指定することができます。

ここでは、 `/modules/module-0.js`、`/modules/module-1.js` など、10 個のモジュールを並列に読み込んで、それぞれがエクスポートする `load` 関数を呼び出しています。


```js
Promise.all(
  Array.from({ length: 10 }).map(
    (\_, index) => import(`/modules/module-${index}.js`),
  ),
).then((modules) => modules.forEach((module) => module.load()));
```

仕様書
---

| Specification |
| --- |
| ECMAScript Language Specification # sec-import-calls |

ブラウザーの互換性
---------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

関連情報
----

* `import` 宣言