NodeJS 速習チュートリアル

Node.js モジュール

1. Node.js のモジュールとは?

モジュールは Node.js アプリケーションのビルディングブロック(構成要素)であり、コードを論理的で再利用可能なコンポーネントに分割して整理することを可能にします。モジュールの導入には以下のメリットがあります:

  • コードを管理しやすいファイル単位に整理できる
  • 機能をカプセル化できる
  • グローバルな名前空間の汚染(Global Namespace Pollution)を防げる
  • コードの保守性と再利用性が向上する

Node.js は、CommonJS(従来型)と ES Modules(ECMAScript モジュール)の 2 つのモジュールシステムをサポートしています。
このページでは CommonJS について解説します。ES Modules については別途解説ページを参照してください。

2. 標準組み込みモジュール (Core Built-in Modules)

Node.js には、バイナリにコンパイル済みの標準組み込みモジュールがいくつか用意されています。
以下は特によく使われるモジュールです:

  • fs: ファイルシステム操作
  • http: HTTP サーバーおよびクライアント機能
  • path: ファイルパスのユーティリティ
  • os: オペレーティングシステムのユーティリティ
  • events: イベントハンドリング
  • util: ユーティリティ関数
  • stream: ストリーム処理
  • crypto: 暗号化機能
  • url: URL のパース(解析)
  • querystring: URL クエリ文字列の処理

組み込みモジュールを使用するには、require() 関数を使用します。

2.1 複数の組み込みモジュールの使用例

独自の Node.js サーバーを構築する場合などの例です:

const http = require('http');

これで、サーバー作成などのモジュール機能が利用可能になります。

2.2 シンプルな HTTP サーバーの例

http.createServer((req, res) => {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end('Hello World!');
}).listen(8080);

3. モジュールの作成とエクスポート

Node.js では、.js 拡張子を持つすべてのファイルがモジュールとして扱われます。モジュールから機能をエクスポートする方法はいくつかあります。

3.1 複数のアイテムをエクスポートする

複数のエクスポートを行うには、exports オブジェクトにプロパティを追加します。

例: utils.js

// 複数の関数を定義
const getCurrentDate = () => new Date().toISOString();

const formatCurrency = (amount, currency = 'USD') => {
  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: currency
  }).format(amount);
};

// 方法 1: 複数のアイテムを個別にエクスポート
exports.getCurrentDate = getCurrentDate;
exports.formatCurrency = formatCurrency;

// 方法 2: オブジェクトとしてまとめてエクスポートする場合
// module.exports = { getCurrentDate, formatCurrency };

3.2 単一のアイテムをエクスポートする

クラスやオブジェクトなど、1 つのアイテムだけをエクスポートする場合は、module.exports に直接代入します。

例: logger.js

class Logger {
  constructor(name) {
    this.name = name;
  }

  log(message) {
    console.log(`[${this.name}] ${message}`);
  }

  error(error) {
    console.error(`[${this.name}] ERROR:`, error.message);
  }
}

// 単一のクラスをエクスポート
module.exports = Logger;

3.3 自作モジュールの使用

require() に相対パスまたは絶対パスを指定して、自作のカスタムモジュールをインポートして利用します。

例: app.js

const http = require('http');
const path = require('path');

// カスタムモジュールのインポート
const { getCurrentDate, formatCurrency } = require('./utils');
const Logger = require('./logger');

// ロガーのインスタンスを作成
const logger = new Logger('App');

// サーバーの作成
const server = http.createServer((req, res) => {
  try {
    logger.log(`${req.url} へのリクエストを受信しました`);

    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.write(`<h1>アプリへようこそ!</h1>`);
    res.write(`<p>現在の時刻: ${getCurrentDate()}</p>`);
    res.write(`<p>フォーマット済みの金額: ${formatCurrency(99.99)}</p>`);
    res.end();
  } catch (error) {
    logger.error(error);
    res.writeHead(500, { 'Content-Type': 'text/plain' });
    res.end('Internal Server Error');
  }
});

// サーバーの起動
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
  logger.log(`サーバーが http://localhost:${PORT} で稼働中です`);
});

4. モジュールのロードとキャッシュ

Node.js は、最初にロードされたときにモジュールをキャッシュします。つまり、2回目以降の require() 呼び出しでは、キャッシュされたバージョンが返されます。

4.1 モジュールの解決(Module Resolution)

require が実行されると、Node.js は以下の順序でモジュールを検索します:

  1. コアモジュール: fs, http など
  2. node_modules フォルダ: インストールされた外部ライブラリ
  3. ローカルファイル: ./../ プレフィックスが付いたパス

ターミナルで実行して確認してみましょう:

node app.js

ブラウザで http://localhost:3000 にアクセスして結果を確認してください。

5. ベストプラクティス

5.1 モジュールの構成

  • モジュールは「単一責任の原則(Single Responsibility)」に基づき、1つの機能に集中させる
  • 意味のあるファイル名やディレクトリ名を使用する
  • 関連する機能をグループ化する
  • モジュールのエントリポイントとして index.js を活用する

5.2 エクスポートのパターン

  • ユーティリティ系には名前付きエクスポート(Named Exports)を優先する
  • 単一クラスのモジュールにはデフォルトエクスポート(module.exports への直接代入)を使用する
  • モジュールの API をドキュメント化する
  • 必要に応じてモジュールの初期化処理を適切に行う

6. まとめ

モジュールは Node.js における重要なコンセプトです。コードを再利用可能で保守性の高いユニットに整理することを可能にします。

モジュールの作成、エクスポート、インポートの方法を効果的に理解することで、スケーラブルで構造化されたアプリケーションを構築できます。

重要なポイント:

  • Node.js はデフォルトで CommonJS モジュールを使用する
  • インポートには require()、エクスポートには module.exports を使用する
  • モジュールは初回ロード後にキャッシュされる
  • 適切なモジュール構成と構造に関するベストプラクティスに従う