概要: このチュートリアルでは、JavaScriptの動的インポートと、それを用いてモジュールを動的にインポートする方法について学習します。
JavaScript動的インポート入門
ES6では、モジュール式のJavaScriptコード開発を可能にするモジュールの概念が導入されました。JavaScriptの動的インポートの仕組みを理解するために、簡単な例から始めましょう。
次の構造を持つプロジェクトがあるとします。
├── index.html
└── js
├── app.js
└── greeting.js
Code 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
キーワードを使用して、デフォルトエクスポートにアクセスします。