2020年2月8日

動的インポート

前の章で説明した`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();

完全な例を以下に示します。

結果
say.js
index.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>
ご注意ください

動的インポートは通常のスクリプトで機能し、`script type="module"`は必要ありません。

ご注意ください

`import()`は関数呼び出しのように見えますが、たまたま括弧を使用する特別な構文です(`super()`に似ています)。

そのため、`import`を変数にコピーしたり、`call/apply`で使用したりすることはできません。関数ではありません。

チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善のための提案がある場合は、コメントする代わりに、GitHubのissueを送信するか、プルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • 数語のコードを挿入するには、`<code>`タグを使用します。複数行の場合は、`<pre>`タグで囲みます。10行を超える場合は、サンドボックス(plnkrjsbincodepen…)を使用します。