JavaScript

JavaScript の静的インポートと動的インポート

投稿日:2019年3月12日 更新日:

1. JavaScript の 2種類のインポート機能(概要)

JavaScript の機能である「静的インポート」と「動的インポート」について簡単にまとめます。

どちらも、モジュールとして作成された JavaScriptファイルを読み込んで利用するための機能です。

まず、ざっとどんな感じで使うのか書いておきます。

1. モジュール側

モジュール側の JavaScriptファイルでは、export 文を使うことにより 関数・オブジェクト・プリミティブな値を外部にエクスポートすることができます(モジュール化できるということです)。

コード例

// 関数を宣言
function myFunction() {
  // ...
}

// 宣言した関数をエクスポート
export { myFunction }; 

2. 呼び出し側

一方、呼び出し側の JavaScript コードでは、import を使ってモジュールを取得することができるのですが、「静的インポート」と「動的インポート」とでは使い方が異なります。

静的インポート

静的インポートの場合は、以下のように import 文を宣言的に使います。

import * as myModule from '/modules/my-module.js';

モジュールが、myModule 変数にインポートされます。

動的インポート

動的インポートの場合は、以下のように import に括弧をつけて関数のようにして使います。

import('/modules/my-module.js')
  .then((module) => {
    // インポートしたモジュールが、module にセットされています
    // module を使った処理を記述します
  });

では、個別に説明していきます。

2. 静的インポート

1. この機能の呼び名

英語の場合、こちらの機能は以下のような呼ばれ方をします。

  • JavaScript modules via script tag ( <script type="module"> )
  • Native JavaScript modules (ES6, ES2015)

動的インポートよりも先に静的インポートができたため、「JavaScript のモジュール機能」のような名前で静的インポートが紹介されていることが多いです(下記参照)。しかし、現時点 (2019年3月) でこの名前を使われた場合は、動的インポートも含まれていると捉えるのが良いでしょう。

2. 特徴

  • JavaScript コードの先頭で、import を使います。
    • トップレベルのスコープでしか使えません。
    • 例えばイベントハンドラ内で使おうとすると、文法エラーになります。
  • Webページ読み込み時に、import するモジュールのファイルが読み込まれます。
  • 基本的には同期実行です。
  • 非同期で実行したい場合は、<script> タグに async という属性を指定します。

3. 仕様

4. ブラウザのサポート状況

5. 使い方

(1) <script> タグに type="module" という属性を指定します。

(2) JavaScriptコードの先頭で import を使い、モジュールを変数に割り当てます。

コード例

<script type="module">
import module from "xxx.js";

module.func1("Hello!");
</script>

6. 実行されるタイミング

以下は仕様書に載っている図です。下から2つが今回該当する項目です。async を指定すると、JSファイルを fetch し終わったら、すぐに非同期で実行します。そのため、この後で示すコードのように、alert() を使っても、パース処理やレンダリングをブロックして止めることなく進めることができます。逆に言うと、静的インポートは async を指定しないと非同期にすることができません。

4.12.1 The script element | HTML Standard より引用
Web

ウェブブラウザがページを取得して表示するまでの流れ

2018.11.05

7. サンプルコード

以下がサンプルコードです。

index.html

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>

    <script type="module" src="main.js" async></script>
  </body>
</html>
  • <script> タグに、type="module" 属性を指定しないと、import が使えません。
  • インポート時に実行されるコードの中に、alert() 関数があるため、async を指定してHTMLのパース処理やレンダリング処理を止めないようにしています。

main.js

import utils from "./utils.js";
utils.say( "Hello, Static Import!");

utils.js

export default {
  say: (msg)=>{
    alert(msg);
  }
};

export の使い方はいくつか種類があり、それに対応して import の書き方も変わってくるのですが、このあたりについては以下の記事などを参考にしてください。

インライン JavaScript

index.html の中に、main.js の内容を書くことも可能です(インライン)。

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>

    <script type="module">
    import utils from "./utils.js";
    utils.say( "Hello, Static Import!");
    </script>
  </body>
</html>

<script type="module"> タグについて

<script> タグに type="module" を指定すると、この内部は1つのモジュール扱いとなります。ここで定義した変数や宣言したクラスなどは、そのままではグローバルになりません。それ以外にもいろいろな違いがあるので注意してください。

参照:JavaScript modules – JavaScript | MDN

8. デモページ

先程のサンプルコードを使ったデモページを用意しました。

デモページ

🔗 Static Import Test

9. 参考情報

3. 動的インポート

1. 特徴

  • import を関数として使います。
  • どこでも使えます。
    • 例えばイベントハンドラ内で、その時の状況に応じたモジュールをインポートすることもできます。
  • import() 実行時に、モジュールのファイルがブラウザからリクエストされ取得されます。
    • 例えばイベントハンドラ内で import() されている場合は、そのWebページを表示した時には、まだモジュールのファイルは取得されません。対象となるイベントが発火したときに初めてモジュールのファイルがリクエストされて取得されます。
  • import の返り値が Promise になっているため、非同期で実行されます。
    • そのため、HTMLのパース処理やレンダリングを邪魔しないコードが書きやすいです。
  • あとからできただけに柔軟で便利です。モジュールをインポートする場合は、まずこちらを検討するのが良いでしょう。

2. 仕様

3. ブラウザのサポート状況

現時点 (2019年3月) では、Firefox, Edge などで使えません。そもそも正式な仕様にもなっていません。

追記 (2021年3月):現在ではサポートされています。

4. 使い方

<script> タグに type="module" 属性を指定する必要はありません。

(1) import に括弧つけた import("xxx.js") の形でモジュールを読み込みます(どこからでも使えます)。

(2) import() が Promise を返すため、そのまま then() メソッドをつないで処理を連ねていきます。また、Promise であることから、await を使うことも可能です。

then()を使ったコード例

<script>
import("xxx.js").then((module) => {

  // module を使った処理を記述します

});
</script>

await を使ったコード例

<script>
(async () => {
  const module = await import('xxx.js')

  // module を使った処理を記述します

})();
</script>

5. 実行されるタイミング

<script> タグで JavaScriptコードを読み込んだらすぐに実行されます。

といっても非同期での実行になるため、メインの処理をブロックしていつまでも止めてしまうようなことにはなりません。

6. サンプルコード

以下がサンプルコードです。

index.html

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>

    <script src="main.js"></script>
  </body>
</html>

main.js

import("./utils.js").then((module) => {
  console.log(module);
  module.default.say("Hello, Dynamic Import!");
});

utils.js

export default {
  say: (msg)=>{
    alert(msg);
  }
};

7. デモページ

先程のサンプルコードを使ったデモページを用意しました。

デモページ

🔗 Dynamic Import Test

8. 参考情報

4. 使い分け

  • 画面を表示する最初のタイミングで、ブロッキング有りの処理をしたい場合は静的インポート(インポートしたモジュールをすぐに使うような場合)。
  • それ以外は基本動的インポートを使えば良さそうです(動的インポートはどこでも使えます)。
  • 但し、現時点 (2019年3月) ではメジャーなブラウザであっても動的インポートをサポートしていないものがありますので、注意してください。
  • 追記 (2021年3月):現在では 動的インポートもメジャーなブラウザでサポートされています。

📂-JavaScript

執筆者:labo


comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

関連記事

JavaScript

npm パッケージのセキュリティをチェックして必要なら対応する

目次1. npm パッケージのセキュリティnpm audit コマンドnpm outdated コマンド2. 実際にこれらのコマンドを利用してみる1. セキュリティのチェックと対応2. 古いパッケージ …

JavaScript

JSON.stringify() の引数に関する忘備録

JavaScript でよく使う JSON.stringify()メソッドですが、第二引数と第三引数の意味を忘れがちなので本ページに記録しておきます。

Web Security

JavaScript の alert は CPUにたいした負荷を掛けないしタブを閉じれば終了します

以下の話題について書きます。 不正プログラム書き込み疑い補導 03月04日 20時04分 クリックすると同じ画面が表示され、消えなくなる不正なプログラムのアドレスをインターネットの掲示板に書き込んだと …

JavaScript

JavaScript による HTTP(S)リクエスト送信のいろいろな書き方

目次1. はじめに2. JSON を取得するコード(1) axios (XMLHttpRequest) (基本形)(2) axios (XMLHttpRequest) (async/await を使用 …

JavaScript

【JavaScript】無名関数とアロー関数とイベントリスナーのthis

目次1. はじめに2. イベントリスナーの登録無名関数を使う場合アロー関数を使う場合3. まとめ4. 参考 1. はじめに あるHTMLにおいて、以下のようにボタンが存在しており、このボタンのクリック …