JavaScript動的インポート

概要: このチュートリアルでは、JavaScriptの動的インポートと、それを用いてモジュールを動的にインポートする方法について学習します。

JavaScript動的インポート入門

ES6では、モジュール式のJavaScriptコード開発を可能にするモジュールの概念が導入されました。JavaScriptの動的インポートの仕組みを理解するために、簡単な例から始めましょう。

次の構造を持つプロジェクトがあるとします。

├── index.html
└── js
   ├── app.js
   └── greeting.jsCode language: plaintext (plaintext)

index.htmlは、jsディレクトリからapp.jsファイルを読み込みます。index.htmlにはボタンが含まれており、ボタンをクリックするとアラートが表示されます。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>JavaScript Dynamic Import</title>
    </head>
    <body>
        <input type="button" value="Click Me" class="btn">
        <script src="js/app.js" type="module"></script>
    </body>
</html>Code language: HTML, XML (xml)

greeting.jsモジュールはsayHi()関数を定義し、エクスポートします(名前付きエクスポート)。

export function sayHi() {
  alert('Hi');
}Code language: JavaScript (javascript)

app.jsモジュールは、greeting.jsモジュールからsayHi関数をインポートします。クラス.btnを持つボタンを選択し、ボタンをクリックしたときにsayHi()関数を呼び出します。

import sayHi from './greeting.js';

const btn = document.querySelector('.btn');
btn.addEventListener('click', () => {
  sayHi();
});Code language: JavaScript (javascript)

ES2020以前は、必要に応じてgreeting.jsモジュールを動的にロードすることはできませんでした。

例えば、次のapp.jsモジュールは、ボタンがクリックされたときのみgreeting.jsモジュールをロードしようとしますが、エラーが発生します。

const btn = document.querySelector('.btn');

btn.addEventListener('click', () => {
  import sayHi from './greeting.js'; // ERROR
  sayHi();
});Code language: JavaScript (javascript)

ES2020では、関数のようなimport()を使用してモジュールの動的インポートが導入されました。構文は以下のとおりです。

import(moduleSpecifier);Code language: JavaScript (javascript)

import()を使用すると、必要に応じてモジュールを動的にインポートできます。

import()の動作について説明します。

  • import()は、import文で使用されるものと同じ形式のモジュール指定子(moduleSpecifier)を受け取ります。さらに、moduleSpecifierは文字列に評価される式にすることができます。
  • import()は、モジュールが完全にロードされると解決されるPromiseを返します。

以下は、import()構文を使用してapp.jsモジュールからgreeting.jsモジュールを動的にロードする方法を示しています。

const btn = document.querySelector('.btn');

btn.addEventListener('click', () => {
  import('./greeting.js')
    .then((greeting) => {
      greeting.sayHi();
    })
    .catch((error) => {
      console.error(error);
    });
});Code language: JavaScript (javascript)

import()Promiseを返すため、このようにapp.jsモジュールでasync/awaitを使用できます。

const btn = document.querySelector('.btn');

btn.addEventListener('click', async () => {
  try {
    let greeting = await import('./greeting.js');
    greeting.sayHi();
  } catch (error) {
    console.log(error);
  }
});
Code language: JavaScript (javascript)

JavaScript import()の実用的なユースケース

import()には、次の実用的なユースケースがあります。

1) オンデマンドでのモジュールの読み込み

アプリケーションの起動時に利用する必要のないモジュールもあります。読み込み時間を改善するために、そのような機能をモジュールに配置し、次のようにimport()を使用してオンデマンドで読み込むことができます。

function eventHandler() {
    import('./module1.js')
        .then((ns) => {
            // use the module 
            ns.func();
        })
        .catch((error) => {
            // handle error
        });
}
Code language: JavaScript (javascript)

2) 条件に基づいたモジュールの読み込み

if-elseなどの条件文の中にimport()を配置すると、特定の条件に基づいてモジュールを読み込むことができます。

次の例では、特定のプラットフォームを対象とするモジュールを読み込んでいます。

if( isSpecificPlatform() ) {
    import('./platform.js')
    .then((ns) => {
        ns=>f();
    });
}Code language: JavaScript (javascript)

3) 計算されたモジュール指定子

モジュール指定子は、実行時にどのモジュールを読み込むかを決定できる式です。

例えば、ユーザーのロケールに基づいてモジュールを読み込み、ユーザーの特定の言語でメッセージを表示することができます。

let lang = `message_${getUserLocale()}.js`;

import(lang)
    .then(...);
Code language: JavaScript (javascript)

import()の詳細

オブジェクトのデストラクチャリングの使用

モジュールに複数の名前付きエクスポートがある場合、オブジェクトのデストラクチャリングを使用してエクスポートされたオブジェクトを受け取ることができます。greeting.jsに2つの関数があるとします。

export function sayHi() {
  alert('Hi');
}

export function bye() {
  alert('Bye');
}Code language: JavaScript (javascript)

app.jsでは、次のようにオブジェクトのデストラクチャリングを使用できます。

const btn = document.querySelector('.btn');

btn.addEventListener('click', async () => {
  try {
    let { sayHi, bye } = await import('./greeting.js');
    sayHi();
    bye();
  } catch (error) {
    console.log(error);
  }
});
Code language: JavaScript (javascript)

複数のモジュールの動的ロード

複数のモジュールを動的にロードするには、Promise.all()メソッドを使用できます。

Promise.all([
    import(module1), 
    import(module2),
     ...])
    .then(([module1,module2,module3]) => {
        // use the modules
    });
Code language: JavaScript (javascript)

デフォルトエクスポートへのアクセス

モジュールにデフォルトエクスポートがある場合、次のようにdefaultキーワードを使用してアクセスできます。

import(moduleSpecifier)
    .then((module) => {
        // access the default export
        console.log(module.default);
    });Code language: JavaScript (javascript)

例えば、名前付きエクスポートをデフォルトエクスポートに変更できます。

export default function sayHi() {
  alert('Hi');
}Code language: JavaScript (javascript)

app.jsファイルでは、モジュール指定子を使用してsayHi関数をインポートし、defaultキーワードを使用してsayHi()関数を呼び出すことができます。

const btn = document.querySelector('.btn');

btn.addEventListener('click', async () => {
  try {
    let greeting = await import('./greeting.js');
    greeting.default();
  } catch (error) {
    console.log(error);
  }
});Code language: JavaScript (javascript)

まとめ

  • JavaScriptのimport()を使用して、モジュールを動的にロードします。
  • import()は、モジュールが完全にロードされると解決されるPromiseを返します。
  • async/awaitを使用して、import()の結果を処理します。
  • Promise.all()メソッドを使用して、複数のモジュールを一度にロードします。
  • オブジェクトのデストラクチャリングを使用して、モジュールのエクスポートされたオブジェクトに変数を代入します。
  • defaultキーワードを使用して、デフォルトエクスポートにアクセスします。
このチュートリアルは役に立ちましたか?