Node.jsにおけるESモジュールのナビゲーション - モダンJavaScriptへのガイド
James Reed
Infrastructure Engineer · Leapcell

Node.jsにおけるモダンJavaScriptモジュールの夜明け
長らく、JavaScript言語にはネイティブなモジュールシステムが 欠けていました。この void は、Node.js環境のCommonJS (最も有名)やブラウザのAMD/RequireJSなど、様々な ソリューションによって埋められました。CommonJSは長年にわたり Node.jsを非常にうまくサポートしてきましたが、JavaScriptの 公式で標準化されたモジュールシステムとしてのESモジュール (ESM)の登場は、新しいパラダイムをもたらしました。 ESMにより、JavaScriptはクライアントサイドとサーバーサイドの 両方の環境でシームレスに機能する統一されたモジュールシステムを 目指すようになりました。
しかし、Node.jsへのESMの統合は、単純な置き換えではありませんでした。 Node.jsにはCommonJS上に構築された巨大なエコシステムがあり、 未来を受け入れると同時に後方互換性を確保するには、 慎重な検討が必要でした。この移行により、Node.jsには デュアルモジュールシステムが共存するようになり、 開発者には選択肢が、時には課題が提示されます。 CommonJSとESMの根本的な違いと、既存プロジェクトを 移行するための戦略を理解することは、モダンで 将来性のあるJavaScriptアプリケーションを書きたい Node.js開発者にとって不可欠です。この記事では、これらの 違いを掘り下げ、実践的な例を提供し、Node.jsプロジェクトで ESMを採用するプロセスをガイドします。
JavaScriptモジュールの理解:CommonJS vs. ESモジュール
ニュアンスを深く掘り下げる前に、CommonJSとESモジュールの 両方のコアコンセプトとメカニズムを明確に理解しましょう。
コア用語
- モジュールシステム: コードを個別の再利用可能なファイル(モジュール)に 整理し、これらのモジュールがどのように相互作用するか(機能の インポートとエクスポート)を定義するメカニズム。
- CommonJS (CJS): 長年Node.jsのデフォルトのモジュールシステム。
モジュールをインポートするために
require()
を、機能のエクスポート のためにmodule.exports
またはexports
を使用します。 - ESモジュール (ESM): ECMAScriptによって指定された、JavaScriptの
公式で標準化されたモジュールシステム。
import
とexport
ステートメントを使用します。 package.json
のtype
フィールド: パッケージ内のファイルの 解釈方法をNode.jsに指示するpackage.json
のフィールド。"module"
に設定すると.js
ファイルはESMとして扱われ、"commonjs"
(またはその不在)はそれらをCommonJSとして扱います。- ファイル拡張子: Node.jsはファイル拡張子を使用してモジュールシステムを
推測します。
.mjs
ファイルはESMとして、.cjs
ファイルはCommonJSとして 扱われ、package.json
のtype
フィールドに関係なく 扱われます。 - デュアルパッケージハザード: パッケージがCommonJSとESMの両方の バージョンを提供する状況で、両方が同じアプリケーションコンテキストで 異なるモジュールシステムでロードされると、 不整合やエラーにつながる可能性があります。
CommonJS:従来のNode.jsアプローチ
CommonJSは同期的に動作します。つまり、モジュールを require()
すると、そのモジュールがロードおよび評価されるまで
Node.jsは実行をブロックします。この同期的な性質は、
ブラウザほどファイルI/Oが重要ではないサーバーサイド環境には
一般的に適しています。
CommonJSでのエクスポート:
module.exports
または exports
を使用して機能を
エクスポートします。
// math.js (CommonJS) function add(a, b) { return a + b; } const subtract = (a, b) => a - b; module.exports = { add, subtract }; // またはexportsに直接割り当てる // exports.add = add; // exports.subtract = subtract;
CommonJSでのインポート:
require()
関数を使用してモジュールをインポートします。
// app.js (CommonJS) const math = require('./math'); console.log(math.add(5, 3)); // 出力: 8 console.log(math.subtract(10, 4)); // 出力: 6
ESモジュール:モダンスタンダード
ESモジュールは非同期になるように設計されており、 Webブラウザにとって重要な、より良い最適化と 非ブロッキングロードを可能にします。Node.jsでは、 ファイルシステムから同期的にロードされる場合でも、 その内部の解決と評価は非同期グラフの トラバーサルに従います。ESMは静的 分析機能を備えており、インポート/エクスポートは 解析時に決定されるため、ツリーシェイキングや より良いツールサポートなどの機能が可能になります。
ESMでのエクスポート:
export
キーワードを使用して機能をエクスポートします。
// math.mjs (ESM) または package.json に "type": "module" を指定した math.js export function add(a, b) { return a + b; } export const subtract = (a, b) => a - b; // デフォルトエクスポート // export default function multiply(a, b) { // return a * b; // }
ESMでのインポート:
import
キーワードを使用してモジュールをインポートします。
// app.mjs (ESM) または package.json に "type": "module" を指定した app.js import { add, subtract } from './math.mjs'; // ファイル拡張子を含める必要がある console.log(add(5, 3)); // 出力: 8 console.log(subtract(10, 4)); // 出力: 6 // デフォルトエクスポートのインポート // import multiply from './math.mjs'; // console.log(multiply(2, 3)); // 出力: 6 // 動的インポート (非同期) async function doCalculations() { const { add } = await import('./math.mjs'); console.log('Dynamic add:', add(10, 5)); } doCalculations();
主要な違いの要約
機能 | CommonJS (CJS) | ESモジュール (ESM) |
---|---|---|
構文 | require() , module.exports , exports | import , export |
ロード | 同期 | 非同期 (静的グラフ分析) |
バインディング | エクスポートされた値のライブコピー | ライブバインディング (コピーではなく参照) |
トップレベルthis | module.exports | undefined |
ファイル拡張子 | .js (デフォルト), .cjs | .mjs , .js ("type": "module" 付き) |
__dirname , __filename | 利用可能 | 直接利用不可、パスには import.meta.url を使用する |
package.json type | デフォルト (または ` |