2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptにおけるモジュール設計戦略:ESModules vs CommonJS、分割・再利用・依存制御の設計論

Posted at

概要

モジュールとは「処理の塊」ではない。
それは責務の単位であり、他との依存関係をコントロールする構造上の境界線である。

本稿では、JavaScriptにおけるモジュール設計を以下の視点から体系化する:

  • ESModules vs CommonJS の根本的違い
  • export/import構文の設計ルール
  • 分割と責務の境界定義
  • 依存関係の明示的設計
  • ルートエントリと内部構造の整理

1. ESModules vs CommonJS:構文と動作の差異

特性 ESModules (ESM) CommonJS (CJS)
構文 import / export require() / module.exports
実行タイミング 静的(パース時に解決) 動的(実行時に解決)
拡張子 .mjs / .js(type:module) .cjs / .js(type:commonjs)
top-level await ✅ 可能 ❌ 不可

✅ ESMが主流だが、Node.jsとの互換性ではCJSが未だ根強い

→ プロジェクト開始時点でESM / CJSどちらを使うかを明示すべき


2. モジュールの構成原則:意味単位での分割

project/
├─ modules/
│   ├─ user/
│   │   ├─ index.ts
│   │   ├─ service.ts
│   │   └─ validator.ts
│   ├─ auth/
│   │   ├─ index.ts
│   │   └─ session.ts
  • ✅ モジュールは機能(feature)単位で分割
  • ❌ utils や common のような横断的な名目だけでまとめない

3. export戦略:構造を公開するか抽象化するか

// user/index.ts
export { getUser, updateUser } from './service';
export { validateUser } from './validator';
  • index.ts で公開APIを整理することで外部依存をコントロール
  • ✅ 内部構造を隠蔽し、意図されたエントリポイントのみ公開

4. 依存関係の設計と制御

  • ✅ モジュール → サブモジュールの一方向依存を維持
  • ❌ 循環依存(A→B→A)は構造崩壊の原因
  • ✅ 共通依存(例:logger / config)はDI(依存注入) or Adapter層に隔離する
// NG
userService  config  userService

// OK
userService  configAdapter  config

5. ESM特有の import/export パターン

// 名前付きエクスポート
export function hello() {}

// デフォルトエクスポート
export default function () {}
// インポート側
import { hello } from './module';
import main from './module';

→ ✅ 名前付きで意図を明示、defaultは1モジュール = 1主要機能がある場合のみ使用


6. top-level await と構造化非同期

// ESMのみで使える構文
const data = await fetchData();
  • ✅ 非同期初期化ロジックをmainエントリで直書き可能
  • ✅ setup用モジュールとして .bootstrap.ts のような命名を採用する例も多い

設計判断フロー

① 実行環境はNode.jsかブラウザか? → ESM/CJSの選択

② 機能単位で責務が切れているか? → modules/ を構造で分割

③ エクスポートする構造は抽象化されているか? → index.tsの活用

④ 依存関係に循環はないか? → 一方向 & Adapter層を設計

⑤ 非同期初期化はどこに書く? → top-level await または明示的setup関数に分離

よくあるミスと対策

❌ util.js に全処理をまとめて import で吸い上げ

→ ✅ 意味単位のモジュールに分割し、単一責務の原則を適用


❌ デフォルトエクスポートが多用され、関数の意図が読めない

→ ✅ 名前付きエクスポートで意図を構文で明示


❌ 内部構造まで全部exportし、外部モジュールからの依存が崩壊

→ ✅ index.ts公開するインターフェースを制限・統制する


結語

モジュールとは、再利用ではなく、“意味の境界線を設計する”ための構造である。

  • 責務ごとに構造を切り
  • エクスポートは意図を明示し
  • 依存を一方向に制御する

JavaScriptにおけるモジュール設計とは、
「プロジェクトの破綻を防ぐための、構造と言語による契約」である。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?