JavaScript モジュール - JavaScript | MDN

例えば下記のような構成で js ファイルがあるとする。

index.html
main.js
modules/
    square.mjs

これを JavaScript モジュール として読み込む場合、下記のようにする。

Load script

<script type="module" src="main.js"></script>

type="module" がミソ。

export & import

// square.mjs
export const name = 'square';
// main.js
import { name } from './modules/square.mjs';

mjs vs js

この記事ではモジュールファイルに .js の拡張子を使用していますが、他の記事では .mjs という拡張子が使用されているのを目にすることがあるかもしれません。例えば、V8 のドキュメントではこれを推奨しています。理由は以下の通りです。

  • どのファイルがモジュールで、どのファイルが通常の JavaScript であるかを明確にすることができます。
  • これにより、Node.js のようなランタイムや Babel のようなビルドツールで、モジュールファイルがモジュールとして解析されるようになります。

しかし、少なくとも今のところは .js を使い続けることにしました。ブラウザでモジュールを正しく動作させるためには、サーバーが text/javascript などの JavaScript MIME タイプを含む Content-Type ヘッダでモジュールを提供していることを確認する必要があります。そうしないと、”The server responded with a non-JavaScript MIME type” のような厳格な MIME タイプチェックエラーが表示され、ブラウザは JavaScript を実行しません。ほとんどのサーバーでは、.js ファイルにはすでに正しい MIME タイプが設定されていますが、.mjs ファイルにはまだ設定されていません。

Dynamic import

動的importの方法。

squareBtn.addEventListener('click', () => {
  import('./modules/square.js').then((Module) => {
    let square1 = new Module.Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, 'blue');
    square1.draw();
    square1.reportArea();
    square1.reportPerimeter();
  })
});

async/await を使って dynamic import も可能。

let module = await import('/modules/my-module.js');

export - JavaScript | MDN

エクスポートされたモジュールは、宣言のあるなしにかかわらず Strict モードで動作します。export 文は、埋め込みスクリプトでは使えません。

2種類のエクスポート方法があります。

  1. 名前付きエクスポート (モジュールごとに 0 以上のエクスポート)
  2. デフォルトエクスポート (モジュールごとに 1 つのエクスポート)
// 個々の機能をエクスポート
export let name1, name2, , nameN; // var, const も
export let name1 = , name2 = , , nameN; // var, const も
export function functionName(){...}
export class ClassName {...}