
CommonJSは2009年初頭にKevin Dangoor氏らが立ち上げた、サーバサイドJavaScriptのための仕様策定プロジェクトおよびそのモジュール仕様のことです。当時ブラウザ向けにしか考えられていなかったJavaScriptを、サーバや汎用スクリプティング言語として使うために、モジュール、ファイルシステム、バイナリといった基本APIを揃えることを目的としていました。そのうちモジュール仕様は同年5月に登場したNode.jsに採用され、requireとmodule.exportsという形で広く普及することになります。ES Modules標準化後も、Node.jsとnpm資産の根幹に根強く残る重要な仕様です。
この記事の目次
- CommonJS策定の動機
- requireとmodule.exportsの仕組み
- ESMとの相互運用の難所
- CommonJSはまだ消えない
- まとめ
CommonJS策定の動機

2009年当時、JavaScriptはブラウザを離れて、サーバやデスクトップアプリの拡張用に使われ始めていました。しかし言語仕様にはモジュールがなく、ファイルI/Oや標準入出力の触り方も処理系ごとにバラバラ。そこでMozilla所属のKevin Dangoor氏は「ServerJS」(後にCommonJSへ改称)という提案を投稿し、サーバサイドJavaScriptに必要な共通基盤を作ろうと呼びかけました。
CommonJSプロジェクトはモジュールだけでなく、Promise/A、Binary、Filesystem、Sockets、Unitテストといった幅広いAPIを仕様化しようとしました。すべてが実装に至ったわけではありませんが、モジュール仕様(Modules/1.0、Modules/1.1)はNode.jsという強力な実装パートナーを得て、事実上のサーバサイドJSモジュール標準として広まっていきます。
requireとmodule.exportsの仕組み

CommonJSモジュールでは、各ファイルが暗黙的に関数でラップされ、module、exports、require、__dirname、__filenameといった変数がローカルスコープに注入されます。module.exports = ...で公開する値を設定し、別ファイルではconst x = require('./mod')のように同期的に読み込みます。ファイルパス解決にはnode_modulesを上位ディレクトリへ辿っていく独特なアルゴリズムが用いられ、これがnpmエコシステム全体の挙動を規定してきました。
requireは同期APIで、呼び出した瞬間にファイルを読み込んでパース・実行します。そのためモジュールは必ず実行コンテキスト上で評価され、副作用も即座に起きる、というシンプルなセマンティクスです。この素朴さがNode.js黎明期の開発スピードを支えた一方、後年のESM互換やバンドラ最適化との折り合いを難しくしました。理解しておくと、Node.jsの細かい挙動の謎が次々に解けていきます。
ESMとの相互運用の難所

ES Modulesが標準化されて十年が経っても、CommonJSのコード資産は膨大に残っています。Node.jsはこの過渡期を生き延びるため、ESMからCommonJSモジュールをimportできるようにしたり、package.jsonのexportsフィールドで条件付きエクスポートを表現できるようにしたりと、両者を橋渡しする仕組みを段階的に整備してきました。
ただし、CommonJSの動的なrequireと、ESMの静的import文ではセマンティクスが本質的に異なります。ESMからrequireを呼ぶには制限が多く、逆にCommonJSからESMを読むには動的import()を使う必要があります。また、CommonJSではmodule.exportsに何でも代入できるのに対し、ESMでは名前付きエクスポートが基本で、デフォルトエクスポートのラッピング方法も処理系ごとに揺れがあります。現実のNode.jsプロジェクトでは、この微妙な差異との戦いが続いています。
CommonJSはまだ消えない

新規プロジェクトはESMで書くのが現代の流儀ですが、CommonJSが消えるわけではありません。Express、Webpack、Jestといった主要OSSにはCommonJSベースで成熟した版が多数残っており、業務システムのコードベースも一足飛びにESM化できる規模ではないことが多いです。Node.jsチームはESM化を推進しつつも、CommonJSサポートを切り捨てる予定はなく、両者は今後も並走することが見込まれます。
むしろ重要なのは、両者の違いを理解し、新規コードはESMで、既存コードは安定運用を優先しつつ徐々にマイグレーション、という現実的な戦略を立てることです。CommonJSを単なる「古い仕組み」として軽視するのではなく、Node.jsエコシステムの歴史的選択として理解し、設計判断に活かす姿勢が、長期的な保守性につながります。
まとめ
CommonJSは2009年にサーバサイドJSの共通基盤を目指して始まったプロジェクトで、そのモジュール仕様がNode.jsで採用されて広く普及しました。requireと module.exportsという同期的でシンプルなモデルは、npm資産の土台となっています。ESM時代となった今もCommonJSは現役で、両者の相互運用の難所を理解しておくことが、Node.js実務では欠かせません。
※本記事はIT用語辞典の手書きドラフトです。公開前に最新情報・出典を確認のうえ加筆修正してください。

コメント