Node.js モジュールインポート

Node.js プロジェクトを書き始めるとき、最初に直面する問題の一つは——モジュール(module)をインポートする方法です。

Node.js では、モジュールとは再利用可能な JavaScript ファイルのことです。モジュール同士はインポート(import)とエクスポート(export)によって相互に通信します。

Node.js エコシステムは主に 2 つのモジュールシステムをサポートしています:CommonJSと ES Modules (ESM)。

モジュールシステム 仕様 ファイル拡張子 インポート方法 エクスポート方法
CommonJS Node.js が初期に使用 .js require() module.exports / exports
ES Module (ESM) ECMAScript 標準 .mjs 或 "type": "module" import export / export default

CommonJS モジュールシステム

CommonJS は Node.js で最も初期に、そして最も広く使われているモジュールシステムです。同期ロード方式を採用しており、モジュールのロード中はプログラムの実行がブロックされ、ロードが完了するまで待機します。

インポートとエクスポート

CommonJS では、あなたはrequire()関数を使ってモジュールをインポートし、module.exports 或 exportsオブジェクトを使ってモジュールをエクスポートします。

エクスポート方法:

math.js ファイルコード:

// math.js
function add(a, b) {
  return a + b;
}

module.exports = { add };
// または:exports.add = add;

インポート方法:

例

// app.js
const math = require('./math.js');

console.log(math.add(2, 3)); // 5

モジュールが外部から自分の内容にアクセスできるようにするには、module.exports または exports を使ってエクスポートする必要があります:

例

// user.js
const name = 'Alice';
const age = 30;

// 方法1:module.exports を使って単一のオブジェクトまたは値をエクスポート
module.exports = {
  name: name,
  age: age,
  sayHello: () => {
    console.log(`Hello, my name is ${name}.`);
  }
};

// 方法2:exports を使って複数の名前付き変数をエクスポート
// exports は module.exports の参照です
exports.name = name;
exports.age = age;
exports.sayHello = () => {
  console.log(`Hello, my name is ${name}.`);
};

インポート方法:

例

// main.js
const user = require('./user.js');

console.log(user.name); // 出力: Alice
user.sayHello(); // 出力: Hello, my name is Alice.

// 分割代入(デストラクチャリング)も直接できます
const { name, age } = require('./user.js');
console.log(name); // 出力: Alice

CommonJS の特徴:

  • 同期ロード:サーバーサイド環境に適しています。モジュールは通常ローカルファイルシステムにあるため、ロードが高速です。
  • 実行時ロード:require()コードの任意の場所で呼び出せるため、条件に応じてモジュールを動的にロードできます。
  • キャッシュ機構:require()ロードされたモジュールはキャッシュされ、2回目のインポート時にはキャッシュから直接読み取られるため、重複ロードが回避されます。

ES Module(ESM)仕様

ESM は JavaScript 公式のモジュール標準であり、非同期ロードを採用し、ブラウザと現代の Node.js アプリケーションで推奨されています。

ESM では、あなたはimportステートメントを使ってモジュールをインポートし、exportステートメントを使ってモジュールをエクスポートします。

ESM を有効にする:Node.js で ESM を使用するには、package.json ファイルに次を追加する必要があります"type": "module"、またはファイル拡張子を.mjs。

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

モジュールをエクスポート:

例

// math.mjs
export function add(a, b) {
  return a + b;
}

export default function multiply(a, b) {
  return a * b;
}

モジュールをインポート:

例

// app.mjs
import multiply, { add } from './math.mjs';

console.log(add(2, 3));      // 5
console.log(multiply(2, 3)); // 6

有効にする方法:

  • ファイル拡張子は.mjs

  • または package.json に次を追加:

    {
      "type": "module"
    }

ESM は 2 つのエクスポート方法をサポートしています:名前付きエクスポート(Named Exports)とデフォルトエクスポート(Default Export)です。

例

// user.mjs

// 名前付きエクスポート
export const name = 'Bob';
export const age = 25;

// デフォルトエクスポート
const sayHello = () => {
  console.log(`Hello, my name is ${name}.`);
};
export default sayHello;

インポート方法:

例

// main.mjs

// 名前付きエクスポートをインポート
import { name, age } from './user.mjs';
console.log(name); // 出力: Bob

// デフォルトエクスポートをインポート
import sayHello from './user.mjs';
sayHello(); // 出力: Hello, my name is Bob.

// 名前付きとデフォルトの両方を同時にインポート
import sayHello, { name } from './user.mjs';
console.log(name);
sayHello();

// すべての名前付きエクスポートをインポートし、オブジェクトのプロパティとして扱う
import * as user from './user.mjs';
console.log(user.name);
user.default(); // デフォルトエクスポートは default プロパティになります

ESM の特徴:

  • 非同期ロード:デフォルトでは非同期ロードであり、メインスレッドをブロックしないため、ブラウザ環境により適しています。ただし、Node.js では通常は同期ロードとして動作します。
  • 静的解析:importとexportステートメントはコードの実行前にモジュールの依存関係を決定できるため、ツール(Webpack、Vite など)はより良い最適化(例えばTree Shaking)。
  • 厳格モード:ESM モジュールはデフォルトで厳格モードで実行されます。

CommonJS と ESM の違い

項目 CommonJS ESM
構文 require / module.exports import / export
ロードメカニズム 実行時同期ロード コンパイル時静的ロード
デフォルトサポート Node.js がデフォルトでサポート 需 .mjs 或 "type": "module"
適したシナリオ バックエンドスクリプト、レガシープロジェクト モダンなフロントエンド・バックエンドプロジェクト、Tree-shaking
混在利用の可否 直接混在できない(追加設定が必要) 直接混在できない(追加設定が必要)

混在利用

Node.js は比較的新しいバージョンで 2 つのモジュールシステムの共存をサポートしています。同じプロジェクト内で CommonJS と ESM を同時に使用できますが、以下の点に注意する必要があります:

  • ESM では直接使用できないrequire()とmodule.exports。
  • CommonJS では直接使用できないimportとexport。
  • ESM で CommonJS モジュールをインポートしたい場合は、直接importステートメントを使用でき、ESM はそれをデフォルトエクスポートとして扱います。

    // commonjs_module.js
    module.exports = { data: 'hello' };
    
    // esm_module.mjs
    import commonModule from './commonjs_module.js';
    console.log(commonModule.data); // 输出: hello
    
  • CommonJS で ESM モジュールをインポートしたい場合は、動的import()関数。

    // esm_module.mjs
    export const name = 'Bob';
    
    // commonjs_module.js
    async function loadESM() {
      const { name } = await import('./esm_module.mjs');
      console.log(name);
    }
    loadESM();
    

ベストプラクティスの推奨

新しいプロジェクトについては、ES Modules(ESM)の使用を強くお勧めします。これは JavaScript の公式標準であるだけでなく、現代のフロントエンドツールチェーン(Vite、Next.js など)との互換性も高く、Tree Shaking などの最適化技術を最大限に活用して、バンドル後のコードサイズを削減できます。

古い CommonJS プロジェクトを保守していて、ESM の機能が必要ない場合は、CommonJS を引き続き使用できます。ただし、新しい依存関係を導入する必要がある場合や ESM の新機能を活用したい場合は、段階的に移行するか、混在モードで移行を進めることを検討できます。

その他の拡張機能