7. モジュール

Node.jsのモジュールシステムの基本を学びます。ESMとCJSのモジュール構文を理解し、export/import、require/module.exportsの使い方を理解します。効率的なコード分割と再利用の方法を学習します。

この章で学べること

  • ファイル分割とモジュール化のメリットを知る
  • ESM(ECMAScript Modules)の基本構文を理解する
  • CJS(CommonJS)の基本構文を理解する
  • ESMとCJSの識別ができる
  • ESMのモジュールを作成することができる

モジュールとは

Node.jsのモジュールシステムは、コードを再利用可能な単位に分割し、整理するための仕組みです。モジュールを使用することで、以下のメリットがあります。

コードの再利用

一度書いたコードを他の場所でも使用できる

保守性の向上

機能ごとに分離されているため、修正や更新が容易

名前空間の分離

変数や関数の名前の衝突を防ぐ

チーム開発の効率化

複数の開発者が異なるモジュールを並行して開発できる

モジュールの使用例

次のコードは、greetモジュールという挨拶をする関数をmain.jsから読み込んで使用する例です。

greet.js

// 挨拶をする関数
export function greet(name) {
  console.log(`こんにちは、${name}!`);
}

main.js

// greet.jsから挨拶をする関数を読み込んで使用する
import { greet } from './greet.js';

greet('忍者');
// 「こんにちは、忍者!」と表示される

関数以外にも定数、クラス、オブジェクトなど様々な種類のコードを読み込んで使うことができます。モジュールを使うことで、同じコードを何度も書く必要がなく、コードを再利用できるようになります。

ESMとCJSについて

モジュール機能を利用するにあたって、ESM(ECMAScript Modules)CJS(CommonJS)について知っておく必要があります。

ESM(ECMAScript Modules)とは

ESMは、JavaScriptの標準的なモジュールシステムです。ES6(ES2015)で導入され、現在のJavaScriptの標準となっています。

構文

import / export

CJS(CommonJS)とは

CJSは、Node.jsで長年使用されてきたモジュールシステムです。ESMが登場する前の標準的なモジュール方式でした。

構文

require() / module.exports

どちらを使うべきか?

どちらを使うべきかは、プロジェクトの要件や目的によって異なります。一般的には、新しいプロジェクトを始める場合はESMを使うことをおすすめします。

ESMを選ぶべき場合

  • 新しいプロジェクトを始める
  • ブラウザでも動作するコードを書く

CJSを選ぶべき場合

  • 既存のレガシープロジェクトを維持する
  • 多くのCJSライブラリを使用する

ESMのモジュール機能について

export(ESM)

export は、モジュールの機能(関数、変数、クラスなど)を公開するためのキーワードです。「このファイルから他のファイルに使ってもらいたい機能を公開する」場合に使用します。exportはESMモジュール構文です。

1. 名前付きエクスポート

名前付きエクスポートは、複数の機能を1つのファイルからエクスポートできる方法です。各機能には固有の名前が付けられ、その名前でインポートする必要があります。

math.js

// 数学の計算をするモジュール
// 足し算の関数
export function add(a, b) {
  return a + b;
}

// 引き算の関数
export function subtract(a, b) {
  return a - b;
}

// 円周率の定数
export const PI = 3.14159;

2. デフォルトエクスポート

デフォルトエクスポートは、1つのファイルから1つだけエクスポートできる特別なエクスポート方法です。そのファイルの「メインの機能」として扱われます。

Calculator.js

// 計算機のクラス
export default class Calculator {
  add(a, b) {
    return a + b;
  }
}

3. 組み合わせて使用

名前付きエクスポートとデフォルトエクスポートは組み合わせて使うことができます。

utils.js

// デフォルトエクスポート
export default function logger(message) {
  console.log(`[LOG] ${message}`);
}

// 名前付きエクスポート
export function formatDate(date) {
  return date.toLocaleDateString();
}

export function formatCurrency(amount) {
  return `¥${amount.toLocaleString()}`;
}

推奨

どちらを使うかで迷ったときは、名前付きエクスポートを使うことをおすすめします。名前付きエクスポートは、コードの明確性、保守性、パフォーマンスの面で多くのメリットがあるため、基本的な選択肢として推奨されます。

import(ESM)

import は、他のファイルからエクスポートされた機能を取り込むためのキーワードです。exportと対になって、モジュールシステムを構成します。importはESMモジュール構文です。

1. 名前付きインポート

名前付きインポートは、名前付きエクスポートされた機能を、その名前で取り込む方法です。

// main.js
import { add, subtract, multiply, PI } from './math.js';

console.log(add(5, 3));      // 8
console.log(subtract(5, 3)); // 2
console.log(multiply(5, 3));  // 15
console.log(PI);              // 3.14159

注意点

  • exportとimportの名前が一致している必要があります
  • 大文字小文字の区別をするため、気をつけましょう

2. エイリアス(別名)の使用

エイリアスとは別名のことです。インポートする機能の名前が被る場合に利用します。

import { add as plus, subtract as minus } from './math.js';

console.log(plus(5, 3));  // add関数が実行される
console.log(minus(5, 3)); // subtract関数が実行される

3. 名前空間インポート

モジュールの機能を全て読み込みたいときに使います。基本的には必要な機能だけをインポートすることを推奨します。

import * as MathUtils from './math.js';

console.log(MathUtils.add(5, 3));      // 8
console.log(MathUtils.subtract(5, 3)); // 2
console.log(MathUtils.multiply(5, 3)); // 15
console.log(MathUtils.PI);             // 3.14159

4. デフォルトインポート

デフォルトインポートは、デフォルトエクスポートされた機能を取り込む方法です。export defaultでエクスポートされた機能を読み込むことができます。波括弧{}は不要です。

import logger from './logger.js';

logger('アプリケーション開始');

デフォルトインポートは名前を自由に決めることができます。

import logger from './logger.js';        // 元の名前
import myLogger from './logger.js';      // 別の名前
import appLogger from './logger.js';     // さらに別の名前

// すべて同じ機能を指している
logger('メッセージ1');
myLogger('メッセージ2');
appLogger('メッセージ3');

CJS(CommonJS)のモジュール機能について

CJS(CommonJS)は、Node.jsで長年使用されてきたモジュールシステムです。ESMが登場する前の標準的なモジュール方式でした。ここでは、基本的な構文について触れておきたいと思います。

CJSの基本的な構文

1. モジュールのエクスポート(module.exports)

モジュールのエクスポートには、module.exports を使います。

math.js

// 数学の計算をするモジュール
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

const PI = 3.14159;

// オブジェクトとしてエクスポート
module.exports = {
  add,
  subtract,
  PI
};

// または個別にエクスポート
module.exports.add = add;
module.exports.subtract = subtract;
module.exports.PI = PI;

2. モジュールのインポート(require())

モジュールのインポートにはrequire()を使います。

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

console.log(math.add(5, 3));      // 8
console.log(math.subtract(5, 3)); // 2
console.log(math.PI);             // 3.14159

実践演習

演習①:ESMとCJSの識別をしよう

以下のコードの中で、ESMとCJSを識別してください。

問題1
export function greet(name) {
  console.log(`こんにちは、${name}!`);
}
問題2
const math = require('./math.js');
問題3
import { add, subtract } from './math.js';
問題4
module.exports = {
  add: add,
  subtract: subtract
};
問題5
export default class Calculator {
  add(a, b) {
    return a + b;
  }
}

演習②:基本的なモジュール作成をしよう

以下の手順で、基本的なモジュールを作成して動作確認をしてください。

手順1: モジュールファイルの作成

以下のコードをmath.jsというファイル名で保存してください。

// math.js - 数学計算のモジュール
// 足し算の関数
export function add(a, b) {
  return a + b;
}

// 引き算の関数
export function subtract(a, b) {
  return a - b;
}

// 掛け算の関数
export function multiply(a, b) {
  return a * b;
}

// 割り算の関数
export function divide(a, b) {
  if (b === 0) {
    throw new Error('ゼロで割ることはできません');
  }
  return a / b;
}

// 円周率の定数
export const PI = 3.14159;
手順2: メインファイルの作成

以下のコードをmain.jsというファイル名で保存してください。

// main.js - モジュールを使用するメインファイル
import { add, subtract, multiply, divide, PI } from './math.js';

console.log('=== 基本的な計算 ===');
console.log('足し算:', add(10, 5));        // 15
console.log('引き算:', subtract(10, 5));   // 5
console.log('掛け算:', multiply(10, 5));   // 50
console.log('割り算:', divide(10, 5));     // 2
console.log('円周率:', PI);                // 3.14159
手順3: 実行と動作確認

以下のコマンドでプログラムを実行してください。

node main.js

期待される出力:

=== 基本的な計算 ===
足し算: 15
引き算: 5
掛け算: 50
割り算: 2
円周率: 3.14159

学習ポイント

  • 名前付きエクスポート: export functionで複数の関数をエクスポート
  • 名前付きインポート: import { }で必要な機能のみをインポート

まとめ

Node.jsのモジュールシステムは、コードの再利用性、保守性、チーム開発の効率性を大幅に向上させます。

  1. ESM(ECMAScript Modules): import / export を使用する現代の標準
  2. CJS(CommonJS): require() / module.exports を使用するレガシー方式
  3. 名前付きエクスポート: 複数の機能をエクスポートできる方法
  4. デフォルトエクスポート: 1つのファイルから1つだけエクスポートする方法

特にESMは現代のJavaScript開発において標準となっており、新しいプロジェクトでは積極的に活用していきましょう。モジュールシステムを適切に使用することで、大規模なアプリケーションでも保守しやすいコードを書くことができます。