JavaScriptにおけるモジュールとは、コードをファイル単位などで分割し、必要な部分をインポート(import)・エクスポート(export)できる仕組みです。ES6ではES Modules
(ESM)と呼ばれる標準モジュールシステムが導入され、import
/export
文が使えるようになりました。それ以前から、Node.jsではrequire
関数とmodule.exports
を使うCommonJSと呼ばれるモジュールシステムが使われており、現在も双方が存在しています。
ES
Modulesではimport
/export
構文によりモジュール間で関数や変数をやり取りします。一方、CommonJSではrequire()
でモジュールを読み込み、module.exports
で外部に公開します。技術的な違いとして、CommonJSはモジュールを同期的にロードしますが、ESMでは基本的に非同期にモジュールを読み込みます。またブラウザではESMがネイティブにサポートされているのに対し、CommonJSモジュールをそのまま読み込むことはできず、Webpackなどのバンドラを使って束ねる必要があります。
Node.js環境でも近年はESMがサポートされており、.mjs
拡張子やpackage.json
に"type": "module"
を指定することでimport
/export
が使えます。新規プロジェクトではES
Modulesの使用が推奨されており、既存のCommonJSとの相互運用も可能ですが、モジュールの種類を混在させる際には注意が必要です。
まずES
Modulesの例として、モジュールを二つ用意し、一方で変数や関数をexport
し、他方でimport
して利用します(ブラウザ環境で実行する場合、<script type="module">
タグ内で動作します)。
/*** utils.js - モジュールファイル ***/
export const pi = 3.14159;
export function circleArea(radius) {
return pi * radius * radius;
}
/*** main.js - エントリポイント ***/
import { pi, circleArea } from "./utils.js";
console.log(pi); // 3.14159
console.log(circleArea(5)); // 78.53975
// デフォルトエクスポートの例
// utils.js 側で: export default function greet() { ... }
// main.js 側で: import greet from "./utils.js";
次に、Node.jsで従来使われていたCommonJSの書き方の例を示します。require
とmodule.exports
を用いて同様の機能を実現しています。
/*** utils.cjs ***/
const pi = 3.14159;
function circleArea(radius) {
return pi * radius * radius;
}
// 複数の値をモジュールの外に公開
module.exports = { pi, circleArea };
/*** main.cjs ***/
const { pi, circleArea } = require("./utils.cjs");
console.log(pi); // 3.14159
console.log(circleArea(5)); // 78.53975
解説: ES
Modules形式では、utils.js
でexport
された定数pi
や関数circleArea
を、main.js
側でimport
によって読み込んで使用しています。このとき、読み込む側ではimport { 名前 }
で対応する名前を指定します。デフォルトエクスポートを使った場合(例ではコメントで記載)、import 任意の名前 from "..."
という書式で読み込みます。ES
Modulesではこれらimport
文はファイル先頭で静的に記述され、モジュールを非同期にロードします。
CommonJS形式では、utils.cjs
側でmodule.exports = { pi, circleArea };
とまとめてエクスポートし、main.cjs
側でrequire("./utils.cjs")
により同期的にモジュールをロードしています。CommonJSのrequire
は関数呼び出しなので任意の場所で実行できる一方、ES
Modulesのimport
はファイルロード時に行われる点が異なります。また、上記の例では拡張子.cjs
を使用していますが、Node.jsでESMを使う場合には.mjs
拡張子にするか、package.json
でモジュールタイプを指定する必要があります。
まとめると、
import
/export
を使用。モジュールは非同期ロード。ブラウザとNode.js(設定有)で使用可能。新規プロジェクトで推奨。require
/module.exports
を使用。モジュールは同期ロード。Node.jsでデフォルト使用。ブラウザでは直接使用不可(バンドラが必要)。
現在では多くの場合ES Modulesを使う方向に統一されつつありますが、Node.jsの既存環境や一部ツールではCommonJSが根強く残っています。両者の違いを理解しつつ、必要に応じて変換や互換性設定を行うことで、モダンなモジュール構成で開発を進めることができます。