script type="module" の使い方

ブラウザで ES Modules を使用するには、script タグに type="module" 属性を追加します。これにより、ブラウザはスクリプトをモジュールとして扱い、import/export 構文を解釈できるようになります。

基本的な使い方

<!-- モジュールとして読み込む -->
<script type="module" src="main.js"></script>
// main.js
import { greet } from './utils.js';
console.log(greet('World'));

インラインモジュール

外部ファイルだけでなく、HTML 内に直接モジュールのコードを書くこともできます。

<script type="module">
  import { format } from './utils.js';
  console.log(format(new Date()));
</script>

通常のスクリプトとの違い

特徴通常のスクリプトtype="module"
実行タイミング即座に実行defer と同様
スコープグローバルモジュールスコープ
厳格モード任意自動適用
thiswindowundefined

defer と同様の動作

モジュールは、HTML のパース完了後に実行されます。これは defer 属性と同じ動作です。

<!-- これらは同じタイミングで実行される -->
<script type="module" src="module.js"></script>
<script defer src="script.js"></script>
通常のスクリプト

HTML のパースをブロックして即座に実行

type="module"

HTML パース完了後に実行(defer 相当)

複数回の読み込み

同じモジュールを複数回指定しても、実際に読み込まれるのは1回だけです。

<script type="module" src="utils.js"></script>
<script type="module" src="utils.js"></script>
<!-- utils.js は1回だけ実行される -->

crossorigin 属性

モジュールはデフォルトで CORS(Cross-Origin Resource Sharing)リクエストとして扱われます。同一オリジンでない場合は、サーバー側で適切な CORS ヘッダーを設定する必要があります。

<!-- 外部ドメインからのモジュール -->
<script type="module" src="https://cdn.example.com/lib.js" crossorigin></script>

async 属性との併用

モジュールでも async 属性を使用できます。この場合、モジュールが読み込まれ次第、即座に実行されます。

<!-- 読み込み完了次第、すぐに実行 -->
<script type="module" async src="analytics.js"></script>
async なし

すべてのモジュールが読み込まれ、HTML パース完了後に順番に実行。

async あり

読み込みが完了したモジュールから順に実行。実行順序は保証されない。

MIME タイプ

サーバーは JavaScript ファイルを正しい MIME タイプで配信する必要があります。

正しい:application/javascript
正しい:text/javascript
誤り:text/plain(モジュールとして認識されない)

ファイルパスの指定

ブラウザでのモジュール指定では、相対パスには ./ または ../ が必要です。

// 正しい
import { func } from './utils.js';
import { helper } from '../lib/helper.js';

// エラー(ブラウザでは裸の指定子は使えない)
import { func } from 'utils.js';

実行例

<!DOCTYPE html>
<html>
<head>
  <title>ES Modules Demo</title>
</head>
<body>
  <h1>Hello Modules</h1>
  
  <script type="module">
    import { message } from './message.js';
    document.querySelector('h1').textContent = message;
  </script>
</body>
</html>

type="module" を使用することで、ビルドツールなしでもブラウザで直接 ES Modules を利用できます。