概要
JavaScriptのモジュール構文には、主に2つの形式が存在する:
- CommonJS(CJS): Node.jsにおける従来の標準
- ESModules(ESM): ECMAScript仕様に基づくモダンな構文
構文の違いは表層に過ぎない。
本質的な違いは、読み込みタイミング、スコープ、ツールチェイン、互換性、設計思想にある。
本記事では、それぞれの違いを体系的に整理し、設計判断に基づく選定フローを提示する。
基本構文の比較
✅ CommonJS(CJS)
// export
module.exports = function greet(name) {
return `Hello, ${name}`;
};
// import
const greet = require('./greet');
-
require
は関数 -
module.exports
またはexports
で出力 - Node.jsが標準で採用
✅ ESModules(ESM)
// export
export function greet(name) {
return `Hello, ${name}`;
}
// import
import { greet } from './greet.js';
- 静的構文 → コンパイル時に依存関係が明確になる
- ブラウザ・モダンNode.jsで標準採用
-
type: "module"
が package.json に必要(Node.js)
構文以外の違い:設計に直結する構造的差異
特性 | CommonJS (CJS) | ESModules (ESM) |
---|---|---|
読み込みタイミング | 実行時 (require) | 静的解析(import) |
ファイル拡張子 |
.js (標準) |
.mjs または type:module
|
スコープ | ファイルスコープ | モジュールスコープ |
this の参照 |
module.exports 指す |
undefined |
並列読み込み | ❌ 遅延されやすい | ✅ 並列処理可能(非同期) |
ツリーシェイキング | ❌ 不可 | ✅ 可 |
top-level await | ❌ 使用不可 | ✅ 使用可能 |
実務的な設計判断のフロー
① モダンな構文で書きたい or ブラウザでも使いたい?
→ Yes → ESM(import/export)
② Node.js 専用かつ旧式プロジェクトに組み込みたい?
→ Yes → CJS(require/module.exports)
③ 動的にモジュールを読み込む必要がある?
→ CJS(requireを関数として使える)
④ ツリーシェイキングや静的解析を重視したい?
→ ESM(import構文の恩恵)
⑤ top-level await が必要?
→ ESM 一択
混在の注意点(Node.js環境)
❌ CJS → ESM の読み込み
// CJSファイルからESMは直接読み込めない
const esm = require('./module.mjs'); // ❌ Error
→ ✅ ダイナミック import を使う必要がある:
(async () => {
const esm = await import('./module.mjs');
})();
❌ ESM → CJS の読み込み
// ESM内では require が存在しない
import pkg from './legacy-cjs.js'; // ✅ これはOK(Node.jsは中でラップする)
→ ✅ createRequire()
を使うことも可能
Top-Level Await のパワー(ESM限定)
// ESMのみ
const data = await fetch('https://api.example.com').then(r => r.json());
console.log(data);
→ ✅ グローバルスコープでの await が書ける → 初期化処理が柔軟に設計できる
ツリーシェイキングと副作用の設計
ESModulesでは、未使用の関数・定数がビルド時に削除される:
export function used() { return '✅'; }
export function unused() { return '❌'; }
→ ✅ unused()
が使われなければ最終バンドルに含まれない(Webpack, Rollup対応)
→ ❌ CommonJSでは全体が含まれる
結語
モジュール構文の選択とは、構文選択ではなくアーキテクチャ選択である。
- 動的 vs 静的
- 同期 vs 非同期
- 柔軟性 vs 最適化
- 互換性 vs 進化
構文の書きやすさだけではなく、プロジェクトの性質・ランタイムの要件・チーム構成を見据えた設計判断が求められる。
構文に振り回されず、設計で選べ。
それがモジュール設計におけるプロフェッショナルな選定基準である。