ECMAScript Module (ESM) とは

編集

ECMAScript Module (以下、ESM) は、JavaScriptの公式なモジュールシステムであり、モダンなJavaScriptアプリケーションの構築において重要な役割を果たします。ESMは、コードをモジュール化し、再利用可能でスケーラブルな構造を提供するための標準的な方法です。

特徴

編集
  • 標準規格: ECMAScript (JavaScript) の公式仕様として採用。
  • 静的構造: モジュールの依存関係がコード解析時に決定される。
  • ツールフレンドリー: Tree Shakingや静的解析に対応。
  • ブラウザネイティブサポート: 近年のブラウザやNode.jsで直接利用可能。

基本的な構文

編集

モジュールのエクスポート

編集

モジュールは、エクスポートを使って他のモジュールにデータや機能を提供します。

名前付きエクスポート

編集

特定の名前を付けてエクスポートします。

math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;

デフォルトエクスポート

編集

モジュールに1つの主要なエクスポートを持たせる場合に使用します。

logger.js
export default function log(message) {
  console.log(message);
}

モジュールのインポート

編集

モジュールを使用するには、importを使います。

名前付きインポート

編集
import { add, subtract } from './math.js';
console.log(add(2, 3));
console.log(subtract(5, 3));

デフォルトインポート

編集
import log from './logger.js';
log('Hello, ESM!');

名前の変更 (エイリアス)

編集
import { add as addition } from './math.js';
console.log(addition(4, 5));

ワイルドカードインポート

編集

モジュール全体を1つのオブジェクトとしてインポートします。

import * as MathUtils from './math.js';
console.log(MathUtils.add(2, 3));
console.log(MathUtils.subtract(5, 2));

ESMの実行環境

編集

ブラウザ

編集

ESMはモダンブラウザでネイティブにサポートされています。HTMLでモジュールを読み込む場合、<script>要素にtype="module"属性を追加します。

<script type="module">
  import { add } from './math.js';
  console.log(add(2, 3));
</script>

ESMに非対応なブラウザのためのフォールバック

編集

古いブラウザがECMAScript Module(ESM)をサポートしていない場合でも、<script>要素のnomodule属性を活用することで、シンプルにフォールバックを提供できます。

<!-- ESMをサポートするブラウザ用 -->
<script type="module" src="./app.js"></script>

<!-- ESMをサポートしないブラウザ用 -->
<script nomodule src="./app.cjs.js"></script>

解説

編集
  • type="module": この属性を持つスクリプトは、ESMとして処理されます。ESMをサポートするブラウザのみがこれを読み込みます。
  • nomodule: この属性を持つスクリプトは、ESMをサポートしないブラウザでのみ実行されます。

利点

編集
  • 簡潔さ: 条件分岐をJavaScriptコードで書く必要がなく、HTML内で分岐を実現できます。
  • 効率性: ESM対応ブラウザと非対応ブラウザの両方に適したスクリプトを簡単に提供できます。

この方法は、特にレガシーブラウザをサポートする必要がある場合に有用です。

相対パスと絶対パス

編集
  • 相対パス: ./module.js または ../module.js
  • 絶対パス: /path/to/module.js または完全なURL https://example.com/module.js

Node.js

編集

Node.jsでは、ESMはpackage.json"type": "module"を追加することで有効化できます。

package.json
{
  "type": "module"
}

実行例

編集
index.mjs
import { add } from './math.js';
console.log(add(1, 2));
node index.mjs

CJS (CommonJS) との違い

編集
主な違い
特徴 ESM CJS
エクスポート方法 export / export default module.exports
インポート方法 import require
読み込みタイミング 静的解析 (ビルド時) 動的解析 (実行時)
非同期性 インポートが非同期 (ブラウザ) 同期的

CJSからESMへの移行

編集
  • Node.jsアプリケーションでは、ESMへの移行を考える際にrequireimportの違いを理解することが重要です。
  • 移行時の注意点:
    • ファイル拡張子を.jsから.mjsに変更するか、package.json"type": "module"を設定する必要があります。
    • __dirname__filenameは直接使用できません。代わりに以下のように取得します:
import { fileURLToPath } from 'url';
import { dirname } from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

実践的な活用

編集

動的インポート

編集

ESMでは、import()を使った動的インポートが可能です。これにより、必要なときにモジュールを非同期で読み込むことができます。

async function loadModule() {
  const { add } = await import('./math.js');
  console.log(add(5, 6));
}

loadModule();

Tree Shaking

編集

ESMの静的構造により、未使用のコードをビルド時に除去できます。これにより、最適化された軽量なバンドルが生成されます。

Web WorkersとESM

編集

Web Workers内でもESMを使用できます。

worker.js
import { add } from './math.js';
self.postMessage(add(3, 4));
main.js
const worker = new Worker('worker.js', { type: 'module' });
worker.onmessage = (event) => {
  console.log(event.data);
};

よくある問題と対処法

編集

ファイル拡張子

編集

ESMでは、import文で拡張子を省略できません。正しい拡張子を指定してください。

// NG
import { add } from './math';

// OK
import { add } from './math.js';

同一ファイルでのCJSとESMの混在

編集

CJSとESMを同一ファイルで混在させることはできません。必要に応じて、モジュール形式を分けるか、動的インポートを検討してください。

まとめ

編集

ESMはJavaScriptの標準モジュールシステムとして、モダンな開発環境において欠かせない存在です。静的解析やブラウザネイティブのサポートにより、効率的なモジュール管理が可能になります。CJSからESMへの移行や、ツールチェーンとの統合を進めることで、よりスケーラブルでモジュール化されたアプリケーションを構築できるでしょう。