Package Manager

JavaScriptパッケージマネージャー完全ガイド: npm, yarn, pnpm, Bun

はじめに

JavaScriptエコシステムにおいて、パッケージマネージャーは開発ワークフローの根幹を支える重要なツールである。パッケージマネージャーは、外部ライブラリやフレームワークの依存関係を管理し、プロジェクトの構築・配布・共有を効率化する役割を担う。

現代のJavaScript開発では、数百から数千のパッケージに依存するプロジェクトが一般的であり、これらの依存関係を手動で管理することは事実上不可能である。パッケージマネージャーは以下の課題を解決する。

  • 依存関係の解決: パッケージ間のバージョン互換性を自動的に解決する
  • 再現性の保証: 異なる環境で同一の依存関係ツリーを再現する
  • セキュリティ管理: 脆弱性のあるパッケージを検出・更新する
  • ワークスペース管理: モノレポ構成でのマルチパッケージ管理を支援する
  • スクリプト実行: ビルド・テスト・デプロイなどのタスクを統一的に管理する

本稿では、JavaScript/Node.jsエコシステムにおける主要な4つのパッケージマネージャー — npmyarnpnpmBun — について、それぞれのアーキテクチャ、特徴、設定方法、ユースケースを包括的に解説する。


1. パッケージマネージャーの歴史と進化

1.1 黎明期: npm の登場 (2010年)

Node.jsの誕生 (2009年) から間もなく、Isaac Z. Schlueterによってnpm (Node Package Manager) が開発された。npmはNode.jsのデフォルトパッケージマネージャーとして同梱され、JavaScriptエコシステムの急成長を牽引した。

初期のnpmは以下の特徴を持っていた。

  • node_modules ディレクトリにパッケージをネスト構造でインストール
  • package.json による依存関係の宣言的管理
  • npmレジストリ (registry.npmjs.org) を中心としたパッケージの公開・配布

しかし、初期のnpmにはいくつかの課題があった。

# 初期のnpmのnode_modules構造 (ネスト構造)
node_modules/
├── package-a/
│   └── node_modules/
│       └── lodash@3.0.0/    # package-aが依存するlodash
├── package-b/
│   └── node_modules/
│       └── lodash@4.0.0/    # package-bが依存するlodash (別バージョン)
└── package-c/
    └── node_modules/
        └── lodash@3.0.0/    # package-cも同じlodashに依存 (重複!)

このネスト構造は、同じパッケージが複数箇所にインストールされる「依存関係の重複」問題を引き起こし、node_modules のサイズが肥大化する原因となった。特にWindowsでは、深くネストされたパスがOSのパス長制限 (260文字) を超えるという問題も発生した。

1.2 npm v3: フラット化の導入 (2015年)

npm v3では、依存関係のフラット化 (hoisting) が導入された。これにより、可能な限りパッケージが node_modules のトップレベルに配置されるようになった。

# npm v3以降のnode_modules構造 (フラット構造)
node_modules/
├── package-a/
├── package-b/
├── package-c/
├── lodash@4.0.0/          # トップレベルに巻き上げ
└── package-a/
    └── node_modules/
        └── lodash@3.0.0/  # バージョン競合がある場合のみネスト

しかし、フラット化には新たな問題が生じた。

  • Phantom Dependencies (幽霊依存): package.json に明示的に宣言していないパッケージがトップレベルに巻き上げられることで、暗黙的にアクセス可能になる
  • 非決定的なインストール: インストール順序によって node_modules の構造が変わる可能性がある

1.3 yarn v1: 決定的インストールの実現 (2016年)

Facebookが開発したyarnは、npmの課題を解決するために登場した。主な改善点は以下の通り。

  • yarn.lock ファイルによる決定的な依存関係解決
  • 並列インストールによる高速化
  • オフラインキャッシュによるネットワーク非依存のインストール
  • ワークスペース機能によるモノレポサポート

yarnの登場はnpmに大きな影響を与え、npm v5 (2017年) では package-lock.json が導入されるなど、npmの改善を促進した。

1.4 pnpm: 効率的なストレージの革新 (2017年)

pnpm (Performant npm) は、ディスク容量とインストール速度の効率化に焦点を当てたパッケージマネージャーである。

pnpmの最大の革新はコンテンツアドレッサブルストレージの採用である。すべてのパッケージはグローバルストアに一度だけ保存され、各プロジェクトの node_modules はシンボリックリンクとハードリンクを使ってグローバルストアを参照する。

# pnpmのストレージ構造
~/.pnpm-store/                    # グローバルストア (コンテンツアドレッサブル)
├── lodash@4.17.21/
│   └── node_modules/lodash/
└── react@18.2.0/
    └── node_modules/react/

project/node_modules/
├── .pnpm/                        # 仮想ストア
│   ├── lodash@4.17.21/
│   │   └── node_modules/
│   │       └── lodash -> ~/.pnpm-store/lodash@4.17.21/  # ハードリンク
│   └── react@18.2.0/
│       └── node_modules/
│           └── react -> ~/.pnpm-store/react@18.2.0/     # ハードリンク
├── lodash -> .pnpm/lodash@4.17.21/node_modules/lodash   # シンボリックリンク
└── react -> .pnpm/react@18.2.0/node_modules/react       # シンボリックリンク

1.5 yarn Berry (v2+): Plug'n'Play の導入 (2020年)

yarn v2 (Berry) は、yarn v1から完全に書き直された新しいアーキテクチャを採用した。最大の変更点はPlug'n'Play (PnP) モードの導入である。

PnPモードでは node_modules ディレクトリを完全に廃止し、代わりに .pnp.cjs ファイルがパッケージの解決マップを管理する。

1.6 Bun: オールインワンツールキットの登場 (2022年)

Jarred SumnerによってBunが開発された。BunはJavaScript/TypeScriptのランタイム、バンドラー、テストランナー、そしてパッケージマネージャーを1つのバイナリに統合したオールインワンツールキットである。

Zig言語とJavaScriptCoreエンジンで実装されたBunは、npmの互換性を保ちながら圧倒的なインストール速度を実現している。


2. アーキテクチャの詳細比較

2.1 レジストリとプロトコル

すべてのパッケージマネージャーは、デフォルトでnpmレジストリ (https://registry.npmjs.org) を使用する。ただし、プライベートレジストリやカスタムレジストリの設定も可能である。

# .npmrc - レジストリ設定 (npm, pnpm共通)
registry=https://registry.npmjs.org/

# スコープ付きパッケージのレジストリ指定
@mycompany:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

# プライベートレジストリの設定例 (Verdaccio, Artifactory等)
@internal:registry=https://registry.internal.example.com/
//registry.internal.example.com/:_authToken=${NPM_TOKEN}
# .yarnrc.yml - yarn Berry のレジストリ設定
npmRegistryServer: "https://registry.npmjs.org"

npmScopes:
  mycompany:
    npmRegistryServer: "https://npm.pkg.github.com"
    npmAuthToken: "${GITHUB_TOKEN}"

2.2 依存関係解決アルゴリズム

各パッケージマネージャーは、依存関係の解決に異なるアルゴリズムを使用する。

npm: 幅優先探索ベースのフラット化

npmは依存関係ツリーを幅優先探索 (BFS) で走査し、可能な限りトップレベルにパッケージを巻き上げる。バージョン競合が発生した場合のみ、ネストされたディレクトリに配置する。

// package.json の依存関係例
{
  "dependencies": {
    "package-a": "^1.0.0",
    "package-b": "^2.0.0"
  }
}
# package-aがlodash@4.17.20に依存
# package-bがlodash@4.17.21に依存
# npm の解決結果:
node_modules/
├── package-a/
├── package-b/
└── lodash@4.17.21/        # 互換性のある最新バージョンがトップレベルに

pnpm: シンボリックリンクベースの厳密な分離

pnpmは各パッケージが自身の依存関係のみにアクセスできるよう、厳密な分離を実現する。

# pnpmの依存関係解決
node_modules/
├── .pnpm/
│   ├── package-a@1.0.0/
│   │   └── node_modules/
│   │       ├── package-a -> <store>/package-a   # 実体へのハードリンク
│   │       └── lodash -> ../../lodash@4.17.20/node_modules/lodash
│   ├── package-b@2.0.0/
│   │   └── node_modules/
│   │       ├── package-b -> <store>/package-b
│   │       └── lodash -> ../../lodash@4.17.21/node_modules/lodash
│   ├── lodash@4.17.20/
│   │   └── node_modules/
│   │       └── lodash -> <store>/lodash@4.17.20
│   └── lodash@4.17.21/
│       └── node_modules/
│           └── lodash -> <store>/lodash@4.17.21
├── package-a -> .pnpm/package-a@1.0.0/node_modules/package-a
└── package-b -> .pnpm/package-b@2.0.0/node_modules/package-b

yarn Berry PnP: 仮想ファイルシステム

yarn BerryのPnPモードでは、パッケージは .yarn/cache ディレクトリにZIPアーカイブとして保存され、.pnp.cjs がパッケージの解決マップを提供する。

// .pnp.cjs の概念的な構造 (簡略化)
module.exports = {
  packageRegistryData: [
    ["package-a", [
      ["npm:1.0.0", {
        packageLocation: "./.yarn/cache/package-a-npm-1.0.0-abc123.zip/",
        packageDependencies: [
          ["lodash", "npm:4.17.20"]
        ]
      }]
    ]],
    ["package-b", [
      ["npm:2.0.0", {
        packageLocation: "./.yarn/cache/package-b-npm-2.0.0-def456.zip/",
        packageDependencies: [
          ["lodash", "npm:4.17.21"]
        ]
      }]
    ]]
  ]
};

2.3 ロックファイルの形式比較

各パッケージマネージャーは異なるロックファイル形式を使用する。

// package-lock.json (npm) - JSON形式
{
  "name": "my-project",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "packages": {
    "": {
      "name": "my-project",
      "version": "1.0.0",
      "dependencies": {
        "lodash": "^4.17.21"
      }
    },
    "node_modules/lodash": {
      "version": "4.17.21",
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5cvA=="
    }
  }
}
# yarn.lock (yarn Berry) - YAML風の独自形式
__metadata:
  version: 8
  cacheKey: 10c0

"lodash@npm:^4.17.21":
  version: 4.17.21
  resolution: "lodash@npm:4.17.21"
  checksum: "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ..."
  languageName: node
  linkType: hard
# pnpm-lock.yaml (pnpm) - YAML形式
lockfileVersion: '9.0'

settings:
  autoInstallPeers: true
  excludeLinksFromLockfile: false

importers:
  .:
    dependencies:
      lodash:
        specifier: ^4.17.21
        version: 4.17.21

packages:
  lodash@4.17.21:
    resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ...}
    engines: {node: '>=0.10.0'}
# bun.lock (Bun) - バイナリ形式 (bun.lockb) またはテキスト形式 (bun.lock)
# Bun v1.2以降ではテキスト形式のbun.lockが利用可能
{
  "lockfileVersion": 0,
  "workspaces": {
    "": {
      "dependencies": {
        "lodash": "^4.17.21"
      }
    }
  },
  "packages": {
    "lodash": ["lodash@4.17.21", "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", {
      "hash": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ..."
    }]
  }
}

3. npm (Node Package Manager) 詳細解説

3.1 概要と現状

npmはNode.jsに同梱されるデフォルトのパッケージマネージャーであり、世界最大のソフトウェアレジストリを運営している。2020年にGitHubに買収され、現在はMicrosoftの傘下にある。

項目詳細
初版リリース2010年1月
開発言語JavaScript (Node.js)
ロックファイルpackage-lock.json
現在のメジャーバージョンnpm v10 (2023年〜)
レジストリ規模200万以上のパッケージ

3.2 インストールとセットアップ

npmはNode.jsとともにインストールされるが、単独でのバージョン管理も可能である。

# Node.jsに同梱されるnpmの確認
node -v    # Node.jsバージョン
npm -v     # npmバージョン

# npmの単独アップデート
npm install -g npm@latest

# 特定バージョンのインストール
npm install -g npm@10.2.0

# Corepack経由でのnpm管理 (Node.js 16.9.0以降)
corepack enable npm

3.3 基本的なコマンド

# プロジェクトの初期化
npm init                    # 対話形式で package.json を作成
npm init -y                 # デフォルト値で即座に作成
npm init @scope/name        # イニシャライザーパッケージを使用

# パッケージのインストール
npm install                 # package.json の全依存関係をインストール
npm install lodash          # 最新バージョンをインストール (dependencies)
npm install lodash@4.17.20  # 特定バージョンを指定
npm install -D typescript   # devDependencies に追加
npm install -g nodemon      # グローバルインストール
npm install --save-exact lodash  # 完全一致バージョンで保存

# パッケージの更新
npm update                  # semverに従って全パッケージを更新
npm update lodash           # 特定パッケージのみ更新
npm outdated                # 更新可能なパッケージ一覧

# パッケージの削除
npm uninstall lodash        # パッケージを削除
npm uninstall -g nodemon    # グローバルパッケージを削除

# 情報の確認
npm list                    # インストール済みパッケージのツリー表示
npm list --depth=0          # トップレベルの依存のみ表示
npm info lodash             # パッケージの詳細情報
npm search keyword          # パッケージの検索

# スクリプトの実行
npm run build               # package.jsonのscripts.buildを実行
npm test                    # scripts.testを実行 (npm run testの短縮形)
npm start                   # scripts.startを実行
npm run dev -- --port 3000  # 引数を渡す

# npx: パッケージの一時実行
npx create-react-app my-app     # インストールせずに実行
npx -p typescript tsc --init    # 特定パッケージの特定コマンドを実行

3.4 package.json の詳細設定

{
  "name": "@mycompany/web-app",
  "version": "2.1.0",
  "description": "企業向けWebアプリケーション",
  "main": "dist/index.js",
  "module": "dist/index.mjs",
  "types": "dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./utils": {
      "import": "./dist/utils.mjs",
      "require": "./dist/utils.js"
    }
  },
  "files": [
    "dist/",
    "README.md",
    "LICENSE"
  ],
  "scripts": {
    "dev": "vite dev",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage",
    "lint": "eslint src/ --ext .ts,.tsx",
    "lint:fix": "eslint src/ --ext .ts,.tsx --fix",
    "format": "prettier --write 'src/**/*.{ts,tsx,json,css}'",
    "typecheck": "tsc --noEmit",
    "prepare": "husky install",
    "precommit": "lint-staged",
    "release": "standard-version",
    "postinstall": "patch-package"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.20.0",
    "@tanstack/react-query": "^5.8.0",
    "zod": "^3.22.0",
    "axios": "^1.6.0"
  },
  "devDependencies": {
    "typescript": "^5.3.0",
    "vite": "^5.0.0",
    "@types/react": "^18.2.0",
    "@types/react-dom": "^18.2.0",
    "vitest": "^1.0.0",
    "@testing-library/react": "^14.1.0",
    "eslint": "^8.55.0",
    "prettier": "^3.1.0",
    "husky": "^8.0.0",
    "lint-staged": "^15.2.0"
  },
  "peerDependencies": {
    "react": ">=17.0.0"
  },
  "peerDependenciesMeta": {
    "react": {
      "optional": false
    }
  },
  "overrides": {
    "semver": ">=7.5.4",
    "lodash": "$lodash"
  },
  "engines": {
    "node": ">=18.0.0",
    "npm": ">=9.0.0"
  },
  "packageManager": "npm@10.2.0",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/mycompany/web-app.git"
  },
  "keywords": ["react", "web", "application"],
  "author": {
    "name": "Development Team",
    "email": "dev@mycompany.com"
  }
}

3.5 .npmrc 設定ファイル

npmの動作は .npmrc ファイルで細かく制御できる。設定は以下の優先順位で読み込まれる: コマンドライン > プロジェクト > ユーザー > グローバル。

# プロジェクトルートの .npmrc

# レジストリ設定
registry=https://registry.npmjs.org/
@mycompany:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

# インストール動作の制御
save-exact=true              # バージョンを完全一致で保存 (^ や ~ を使わない)
engine-strict=true           # engines制約を厳密にチェック
fund=false                   # npm fund メッセージを非表示
audit=true                   # インストール時に自動でaudit実行
loglevel=warn                # ログレベル (silent, error, warn, notice, http, info, verbose, silly)

# パフォーマンス設定
prefer-offline=true          # キャッシュを優先使用
fetch-retries=3              # ネットワークリトライ回数
fetch-timeout=60000          # タイムアウト (ミリ秒)
maxsockets=15                # 同時接続数

# セキュリティ設定
ignore-scripts=false         # postinstall等のスクリプト実行制御
strict-ssl=true              # SSL証明書の検証
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

# プロキシ設定 (企業環境向け)
# proxy=http://proxy.company.com:8080
# https-proxy=http://proxy.company.com:8080
# no-proxy=localhost,127.0.0.1,.company.com

3.6 npm ワークスペース

npm v7以降でワークスペース機能がサポートされた。

// ルートの package.json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}
# ワークスペースの操作
npm install                             # 全ワークスペースの依存をインストール
npm run build --workspaces              # 全ワークスペースでbuildを実行
npm run build -w packages/core          # 特定ワークスペースのみ実行
npm run test --workspace=packages/core  # 特定ワークスペースのテスト

# ワークスペースへのパッケージ追加
npm install lodash -w packages/core     # 特定ワークスペースにインストール

# ワークスペース一覧の表示
npm ls --workspaces --depth=0
# モノレポのディレクトリ構造例
my-monorepo/
├── package.json              # ルート (workspaces定義)
├── package-lock.json         # 共有ロックファイル
├── node_modules/             # 共有node_modules
├── apps/
│   ├── web/
│   │   ├── package.json
│   │   └── src/
│   └── api/
│       ├── package.json
│       └── src/
└── packages/
    ├── core/
    │   ├── package.json
    │   └── src/
    ├── ui/
    │   ├── package.json
    │   └── src/
    └── utils/
        ├── package.json
        └── src/

3.7 npm のセキュリティ機能

# セキュリティ監査
npm audit                     # 脆弱性レポートの表示
npm audit fix                 # 自動修正可能な脆弱性を修正
npm audit fix --force         # メジャーバージョンアップを含む強制修正
npm audit --json              # JSON形式で出力
npm audit --production        # 本番依存のみ監査
npm audit signatures          # パッケージ署名の検証

# パッケージの来歴確認
npm provenance                # パッケージのビルド来歴を確認

4. yarn 詳細解説

4.1 yarn Classic (v1) と yarn Berry (v2+)

yarnには2つの大きく異なるバージョンラインが存在する。

項目yarn Classic (v1)yarn Berry (v2+)
アーキテクチャnode_modules ベースPlug'n'Play (PnP) デフォルト
設定ファイル.yarnrc.yarnrc.yml
プラグインなしプラグインシステム
ワークスペース基本サポート高度なサポート (constraints等)
ステータスメンテナンスモードアクティブ開発

4.2 yarn Berry のインストールとセットアップ

# Corepack経由でのインストール (推奨)
corepack enable
corepack prepare yarn@4.1.0 --activate

# プロジェクトでのyarnバージョン設定
yarn set version stable         # 最新安定版を設定
yarn set version 4.1.0          # 特定バージョンを設定
yarn set version from sources   # ソースからビルド

# バージョン確認
yarn --version

4.3 yarn Berry の基本コマンド

# プロジェクトの初期化
yarn init                       # 対話形式で初期化
yarn init -2                    # yarn v2+で初期化

# パッケージのインストール
yarn install                    # 全依存関係をインストール
yarn add lodash                 # 依存関係に追加
yarn add lodash@4.17.21         # 特定バージョン
yarn add -D typescript          # devDependenciesに追加
yarn add -P react               # peerDependenciesに追加
yarn add -E lodash              # 完全一致バージョン (exactバージョン)
yarn add @types/node@^20        # スコープ付きパッケージ

# パッケージの更新
yarn up lodash                  # 最新バージョンに更新
yarn up lodash@^4.17.0          # 範囲内で更新
yarn up '*'                     # 全パッケージを更新
yarn up --interactive           # 対話形式で更新

# パッケージの削除
yarn remove lodash

# 情報の確認
yarn info lodash                # パッケージ情報
yarn why lodash                 # なぜインストールされているか
yarn dlx create-react-app my-app  # 一時実行 (npx相当)

# スクリプトの実行
yarn build                      # scripts.build を実行
yarn test                       # scripts.test を実行
yarn run dev --port 3000        # 引数付きで実行

4.4 .yarnrc.yml の設定

# .yarnrc.yml - yarn Berry の設定ファイル

# Node linker の設定 (重要)
nodeLinker: pnp                  # PnP (デフォルト) | pnpm | node-modules

# PnP設定
pnpMode: strict                  # strict | loose (looseは暗黙の依存を許容)
pnpEnableEsmLoader: true         # ESMローダーの有効化

# キャッシュ設定
enableGlobalCache: false         # プロジェクトローカルキャッシュを使用
cacheFolder: ./.yarn/cache       # キャッシュディレクトリ
compressionLevel: mixed          # 圧縮レベル (0, mixed, default)

# レジストリ設定
npmRegistryServer: "https://registry.npmjs.org"
npmScopes:
  mycompany:
    npmRegistryServer: "https://npm.pkg.github.com"
    npmAuthToken: "${GITHUB_TOKEN}"
    npmAlwaysAuth: true

# Telemetry
enableTelemetry: false

# チェックサムの動作
checksumBehavior: update         # throw | update | ignore | reset

# パッケージ拡張 (依存関係の修正)
packageExtensions:
  "react-scripts@*":
    peerDependencies:
      eslint: "*"
  "some-broken-package@*":
    dependencies:
      missing-dep: "^1.0.0"

# プラグインの読み込み
plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs
    spec: "@yarnpkg/plugin-typescript"
  - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
    spec: "@yarnpkg/plugin-workspace-tools"

4.5 Plug'n'Play (PnP) の詳細

PnPモードはyarn Berryの最も革新的な機能である。

# PnPモードのプロジェクト構造
my-project/
├── .pnp.cjs                    # パッケージ解決マップ
├── .pnp.loader.mjs             # ESMローダー
├── .yarn/
│   ├── cache/                  # パッケージキャッシュ (ZIPファイル)
│   │   ├── lodash-npm-4.17.21-abc123.zip
│   │   ├── react-npm-18.2.0-def456.zip
│   │   └── ...
│   ├── plugins/                # インストール済みプラグイン
│   ├── releases/               # yarn本体のバイナリ
│   │   └── yarn-4.1.0.cjs
│   ├── sdks/                   # エディタSDK
│   └── unplugged/              # PnP非対応パッケージ (展開済み)
├── .yarnrc.yml
├── package.json
└── yarn.lock
# PnPモードでの注意事項
# エディタ(VS Code等)でPnPを使うにはSDKのインストールが必要
yarn dlx @yarnpkg/sdks vscode

# PnP非対応パッケージの展開
yarn unplug package-name

# node_modulesモードへのフォールバック
# .yarnrc.yml で nodeLinker: node-modules を設定
// .vscode/settings.json - VS CodeでPnPを使用する場合
{
  "typescript.tsdk": ".yarn/sdks/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true,
  "search.exclude": {
    "**/.yarn": true,
    "**/.pnp.*": true
  },
  "eslint.nodePath": ".yarn/sdks"
}

4.6 yarn ワークスペースの高度な機能

# ワークスペース操作
yarn workspaces list                    # ワークスペース一覧
yarn workspaces foreach run build       # 全ワークスペースでビルド
yarn workspaces foreach -pt run build   # 並列 + トポロジカル順序でビルド
yarn workspaces foreach --since run test  # 変更のあったワークスペースのみテスト

# 特定ワークスペースでの操作
yarn workspace @mycompany/core add lodash
yarn workspace @mycompany/web run build

# ワークスペース間の依存関係
yarn workspace @mycompany/web add @mycompany/core@workspace:*
# constraints.pro - Prolog ベースのワークスペース制約 (yarn Berry)
% すべてのワークスペースで同じバージョンのTypeScriptを使用する制約
gen_enforced_dependency(WorkspaceCwd, 'typescript', '5.3.3', devDependencies) :-
  workspace_has_dependency(WorkspaceCwd, 'typescript', _, devDependencies).

% React のバージョンを統一
gen_enforced_dependency(WorkspaceCwd, 'react', '^18.2.0', dependencies) :-
  workspace_has_dependency(WorkspaceCwd, 'react', _, dependencies).

% プライベートパッケージは必ず private: true
gen_enforced_field(WorkspaceCwd, 'private', 'true') :-
  \+ workspace_field(WorkspaceCwd, 'name', '@mycompany/published-package').
# 制約のチェック
yarn constraints          # 制約違反を確認
yarn constraints --fix    # 自動修正

5. pnpm 詳細解説

5.1 概要と特徴

pnpmは「Performant npm」の略で、ディスク効率とインストール速度に最適化されたパッケージマネージャーである。

項目詳細
初版リリース2017年
開発言語TypeScript
ロックファイルpnpm-lock.yaml
現在のメジャーバージョンpnpm v9 (2024年〜)
主要な採用例Vue.js, Vite, Element Plus, Turborepo

5.2 コンテンツアドレッサブルストレージの仕組み

pnpmの最大の特徴は、コンテンツアドレッサブルストレージ (Content-Addressable Storage, CAS) である。

# グローバルストアの場所を確認
pnpm store path
# macOS: ~/Library/pnpm/store/v3
# Linux: ~/.local/share/pnpm/store/v3
# Windows: %LOCALAPPDATA%/pnpm/store/v3

# ストアの管理コマンド
pnpm store status           # ストアの整合性チェック
pnpm store prune            # 未使用パッケージをストアから削除
pnpm store add lodash@4.17.21  # 明示的にストアに追加
# CASの内部構造
~/.local/share/pnpm/store/v3/
├── files/
│   ├── 00/
│   │   ├── 1a2b3c4d5e6f...    # ファイルのSHA-512ハッシュ名
│   │   └── 7a8b9c0d1e2f...
│   ├── 01/
│   │   └── ...
│   └── ff/
│       └── ...
└── tmp/

この仕組みにより、同じファイルはストレージ全体で1つだけ保存される。例えば、10個のプロジェクトが lodash@4.17.21 を使用していても、ディスク上には1つのコピーしか存在しない。

5.3 インストールとセットアップ

# インストール方法
# 方法1: Corepack (Node.js 16.13以降)
corepack enable
corepack prepare pnpm@9.1.0 --activate

# 方法2: npm経由
npm install -g pnpm

# 方法3: スタンドアロンスクリプト
curl -fsSL https://get.pnpm.io/install.sh | sh -

# 方法4: Homebrew (macOS)
brew install pnpm

# バージョン確認
pnpm --version

5.4 基本的なコマンド

# プロジェクトの初期化
pnpm init                        # package.json を作成

# パッケージのインストール
pnpm install                     # 全依存関係をインストール
pnpm add lodash                  # dependenciesに追加
pnpm add -D typescript           # devDependenciesに追加
pnpm add -O jest                 # optionalDependenciesに追加
pnpm add --save-peer react       # peerDependenciesに追加
pnpm add lodash@4.17.21          # 特定バージョン
pnpm add -g nodemon              # グローバルインストール
pnpm add -E lodash               # 完全一致バージョン

# パッケージの更新
pnpm update                      # 全パッケージを更新
pnpm update lodash               # 特定パッケージを更新
pnpm update --interactive        # 対話形式で更新
pnpm update --latest             # semver範囲を無視して最新に更新
pnpm outdated                    # 更新可能なパッケージ一覧

# パッケージの削除
pnpm remove lodash               # 依存関係から削除
pnpm remove -g nodemon           # グローバルから削除

# 情報の確認
pnpm list                        # インストール済みパッケージ
pnpm list --depth=0              # トップレベルのみ
pnpm why lodash                  # 依存元の確認

# スクリプトの実行
pnpm run build                   # スクリプト実行
pnpm build                       # run は省略可能
pnpm test                        # テスト実行
pnpm dlx create-react-app my-app # 一時実行 (npx相当)
pnpm exec tsc --noEmit           # ローカルバイナリの実行

5.5 .npmrc による pnpm 設定

pnpmは .npmrc ファイルでnpmと共通の設定に加え、pnpm固有の設定が可能である。

# .npmrc - pnpm固有の設定

# ストレージ設定
store-dir=~/.pnpm-store          # グローバルストアの場所
virtual-store-dir=node_modules/.pnpm  # 仮想ストアの場所
modules-dir=node_modules         # node_modulesの場所

# リンク設定
symlink=true                     # シンボリックリンクの使用
node-linker=hoisted              # hoisted | isolated | pnp
                                 # isolated がデフォルト (pnpm独自の厳密構造)
                                 # hoisted は npm互換のフラット構造

# 依存関係の制御
auto-install-peers=true          # peerDependenciesの自動インストール
strict-peer-dependencies=false   # peerDependencies不一致でエラーにしない
resolve-peers-from-workspace-root=true  # ワークスペースルートからpeerを解決

# Hoisting制御
hoist=true                       # パッケージの巻き上げ
hoist-pattern=['*']              # 巻き上げ対象パターン
public-hoist-pattern=['*eslint*', '*prettier*']  # publicに巻き上げるパターン
shamefully-hoist=false           # npmと同じフラット構造にする (非推奨)

# セキュリティ
ignore-scripts=false             # ライフサイクルスクリプトの制御
side-effects-cache=true          # サイドエフェクトのキャッシュ

# パフォーマンス
prefer-frozen-lockfile=true      # CI環境でロックファイル変更を禁止
lockfile=true                    # ロックファイルの生成
prefer-offline=false             # オフライン優先

5.6 pnpm-workspace.yaml

pnpmのワークスペース設定は pnpm-workspace.yaml で管理する。

# pnpm-workspace.yaml
packages:
  # packages/ 配下のすべてのパッケージ
  - 'packages/*'
  # apps/ 配下のすべてのアプリケーション
  - 'apps/*'
  # tools/ 配下の特定ディレクトリ
  - 'tools/cli'
  - 'tools/scripts'
  # 除外パターン
  - '!**/test/**'
  - '!**/__mocks__/**'

catalog:
  # パッケージカタログ (pnpm v9+)
  # ワークスペース全体で共有するバージョンを定義
  react: ^18.2.0
  react-dom: ^18.2.0
  typescript: ^5.3.0
  vitest: ^1.0.0
  '@types/node': ^20.10.0
// packages/core/package.json - カタログの使用例
{
  "name": "@mycompany/core",
  "dependencies": {
    "react": "catalog:"        // カタログで定義されたバージョンを使用
  },
  "devDependencies": {
    "typescript": "catalog:",
    "vitest": "catalog:"
  }
}
# pnpmのワークスペース操作
pnpm install                                    # 全ワークスペースの依存をインストール
pnpm --filter @mycompany/core add lodash        # 特定ワークスペースに追加
pnpm --filter @mycompany/core run build         # 特定ワークスペースでビルド
pnpm -r run build                               # 全ワークスペースで再帰的にビルド
pnpm --filter "...@mycompany/web" run build     # 依存関係も含めてビルド
pnpm --filter "./packages/**" run test          # ディレクトリパターンでフィルタ
pnpm --filter "...[origin/main]" run build      # 変更のあったパッケージのみ

# ワークスペース間の依存
pnpm --filter @mycompany/web add @mycompany/core@workspace:*

# 並列実行
pnpm -r --workspace-concurrency=4 run build     # 最大4並列でビルド

5.7 pnpm の厳密な依存関係分離

pnpmの最大のセキュリティ上の利点は、厳密な依存関係分離である。

// pnpm使用時: package.json に宣言していないパッケージにはアクセスできない

// package.json の dependencies に "express" のみを宣言している場合
const express = require('express');       // OK: 明示的に依存宣言済み
const bodyParser = require('body-parser'); // ERROR: expressの内部依存だがアクセス不可
// Error: Cannot find module 'body-parser'

// npmの場合はbody-parserがhoistingによりアクセス可能 (phantom dependency)

6. Bun パッケージマネージャー詳細解説

6.1 概要と特徴

Bunは、Jarred Sumnerが開発したJavaScript/TypeScriptのオールインワンツールキットである。ランタイム、バンドラー、テストランナー、パッケージマネージャーを単一のバイナリに統合している。

項目詳細
初版リリース2022年 (v1.0: 2023年9月)
開発言語Zig, C++
JavaScriptエンジンJavaScriptCore (Safari/WebKitと同じ)
ロックファイルbun.lock (テキスト) / bun.lockb (バイナリ)
対応OSmacOS, Linux, Windows (WSL)

6.2 Bun のアーキテクチャ

Bunが高速な理由は以下のアーキテクチャに基づく。

┌─────────────────────────────────────────┐
│              Bun Runtime                 │
├─────────────┬─────────┬─────────────────┤
│   Package   │ Bundle  │  Test Runner    │
│   Manager   │  r      │                 │
├─────────────┴─────────┴─────────────────┤
│          JavaScriptCore Engine           │
├─────────────────────────────────────────┤
│              Zig + C++                   │
├─────────────────────────────────────────┤
│     OS-level I/O (io_uring / kqueue)    │
└─────────────────────────────────────────┘
  • Zig言語: メモリ安全性と低レベル最適化を両立
  • JavaScriptCore: V8と異なるアプローチで高速なJavaScript実行
  • ネイティブI/O: Linuxのio_uring、macOSのkqueueを直接使用
  • 並列ダウンロード: システムレベルの非同期I/Oによる高速なパッケージダウンロード

6.3 インストールとセットアップ

# インストール方法
# 方法1: 公式インストールスクリプト
curl -fsSL https://bun.sh/install | bash

# 方法2: Homebrew (macOS)
brew install oven-sh/bun/bun

# 方法3: npm (Node.jsが必要)
npm install -g bun

# バージョン確認
bun --version

# アップグレード
bun upgrade
bun upgrade --canary    # 最新のCanaryバージョン

6.4 基本的なコマンド

# プロジェクトの初期化
bun init                          # package.json を作成 (TypeScript対応)

# パッケージのインストール
bun install                       # 全依存関係をインストール
bun add lodash                    # dependenciesに追加
bun add -d typescript             # devDependenciesに追加 (-d は -D/--dev)
bun add -p react                  # peerDependenciesに追加
bun add lodash@4.17.21            # 特定バージョン
bun add -g nodemon                # グローバルインストール
bun add --exact lodash            # 完全一致バージョン

# パッケージの更新
bun update                        # 全パッケージを更新
bun update lodash                 # 特定パッケージを更新
bun outdated                      # 更新可能なパッケージ一覧

# パッケージの削除
bun remove lodash                 # 依存関係から削除
bun remove -g nodemon             # グローバルから削除

# スクリプトの実行
bun run build                     # スクリプト実行
bun run dev                       # 開発サーバー起動
bun --bun run dev                 # Node.js の代わりに Bun ランタイムで実行

# TypeScriptの直接実行
bun run src/index.ts              # TypeScriptを直接実行 (トランスパイル不要)
bun run script.tsx                # TSXも直接実行可能

# パッケージの一時実行 (bunx = npx相当)
bunx create-react-app my-app
bunx --bun vitest                 # Bunランタイムで実行

6.5 Bun のパッケージマネージャー固有の機能

# ロックファイルの形式選択
# bunfig.toml で設定
# bunfig.toml - Bun の設定ファイル

[install]
# ロックファイル形式
lockfile = "bun.lock"             # テキスト形式 (Git-friendly, Bun v1.2+)
# lockfile = "bun.lockb"          # バイナリ形式 (高速だがGit diff不可)

# 省略可能な依存関係のインストール
optional = true

# peerDependenciesの自動インストール
peer = true

# devDependenciesのインストール (production環境で無効化)
dev = true

# レジストリ設定
registry = "https://registry.npmjs.org/"

# スコープ付きレジストリ
[install.scopes]
"@mycompany" = { token = "$GITHUB_TOKEN", url = "https://npm.pkg.github.com/" }

# キャッシュ設定
[install.cache]
dir = "~/.bun/install/cache"
disable = false

# ライフサイクルスクリプトの制御
[install.lifecycle]
ignore = ["postinstall"]          # 特定のスクリプトを無視

# パッケージのオーバーライド (npm の overrides 相当)
[overrides]
"semver" = ">=7.5.4"

6.6 Bun ワークスペース

// ルートの package.json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}
# ワークスペース操作
bun install                               # 全ワークスペースの依存をインストール
bun add lodash --filter @mycompany/core   # 特定ワークスペースに追加
bun run --filter '@mycompany/*' build     # パターンマッチでビルド

6.7 Bun のパフォーマンスベンチマーク

# ベンチマーク例 (プロジェクトサイズ: 中規模 React アプリ)
# キャッシュなし、ロックファイルあり

# npm install:     ~25秒
# yarn install:    ~18秒
# pnpm install:    ~12秒
# bun install:     ~3秒

# キャッシュあり
# npm install:     ~8秒
# yarn install:    ~5秒
# pnpm install:    ~4秒
# bun install:     ~0.5秒

※ ベンチマーク結果はプロジェクトの規模、ネットワーク環境、ハードウェアによって大きく異なる。


7. 包括的な比較表

7.1 機能比較

機能npmyarn BerrypnpmBun
デフォルトインストールNode.js同梱Corepack別途インストール別途インストール
ロックファイルpackage-lock.jsonyarn.lockpnpm-lock.yamlbun.lock / bun.lockb
ストレージ方式フラットPnP (ZIP) / フラットCAS + シンボリックリンクフラット
ワークスペースv7+高度なサポートフィルタリング充実基本サポート
Phantom Dependencies発生するPnPで防止デフォルトで防止発生する
オフライン対応キャッシュZero-Installsストアキャッシュ
プラグインシステムなしありなしなし
セキュリティ監査npm audityarn npm auditpnpm audit限定的
モノレポツール連携基本高度Turborepo, Nx基本
パッチ機能patch-packageyarn patchpnpm patchbun patch
ライセンスチェックサードパーティプラグインサードパーティなし

7.2 パフォーマンス比較

指標npmyarn Berry (PnP)pnpmBun
初回インストール速度遅い中程度速い最速
キャッシュありインストール中程度速い (Zero-Install)速い最速
ディスク使用量小 (ZIP圧縮)最小 (CAS)
CI/CDパフォーマンス中程度速い速い最速
メモリ使用量中程度中程度低い低い

7.3 エコシステム互換性

互換性npmyarn BerrypnpmBun
npm互換性基準高い (node-modules linker)高い (shamefully-hoist)高い
TypeScript対応通常通常通常ネイティブサポート
ESM対応完全完全完全完全
Docker最適化通常良好良好良好
CI/CD連携全プラットフォーム全プラットフォーム全プラットフォーム一部制限あり
Windows対応完全完全完全WSL推奨

8. ベストプラクティスと実践的な設定例

8.1 CI/CD 環境での最適化

npm の CI 設定

# GitHub Actions - npm
name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci                    # clean installを使用 (ロックファイル厳密)
      - run: npm test
      - run: npm run build

yarn Berry の CI 設定

# GitHub Actions - yarn Berry
name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          # cacheKey はyarn.lockのハッシュ
      - name: Enable Corepack
        run: corepack enable
      - name: Install dependencies
        run: yarn install --immutable   # ロックファイルの変更を禁止
      - run: yarn test
      - run: yarn build

pnpm の CI 設定

# GitHub Actions - pnpm
name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v2
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile  # ロックファイルの変更を禁止
      - run: pnpm test
      - run: pnpm build

Bun の CI 設定

# GitHub Actions - Bun
name: CI
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v1
        with:
          bun-version: latest
      - run: bun install --frozen-lockfile
      - run: bun test
      - run: bun run build

8.2 Docker での最適化

# ---- npm ----
FROM node:20-slim AS builder
WORKDIR /app

# 依存関係ファイルのみ先にコピー (レイヤーキャッシュ活用)
COPY package.json package-lock.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

FROM node:20-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]
# ---- pnpm ----
FROM node:20-slim AS builder
WORKDIR /app

# pnpmのインストール
RUN corepack enable && corepack prepare pnpm@9 --activate

# pnpm fetch: ロックファイルだけでストアを事前構築
COPY pnpm-lock.yaml ./
RUN pnpm fetch

# ソースコードのコピーとインストール
COPY . .
RUN pnpm install --offline --frozen-lockfile
RUN pnpm build

# プロダクションイメージ
FROM node:20-slim
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@9 --activate
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
CMD ["node", "dist/index.js"]
# ---- Bun ----
FROM oven/bun:1 AS builder
WORKDIR /app

COPY bun.lock package.json ./
RUN bun install --frozen-lockfile --production

COPY . .
RUN bun run build

FROM oven/bun:1-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
CMD ["bun", "run", "dist/index.js"]

8.3 Corepack によるパッケージマネージャーのバージョン管理

Corepackは、Node.js 16.9.0以降に同梱されたパッケージマネージャーのバージョン管理ツールである。

# Corepackの有効化
corepack enable

# package.json の packageManager フィールド
{
  "name": "my-project",
  "packageManager": "pnpm@9.1.0"
}
# Corepackの動作
# pnpm@9.1.0がインストールされていなければ自動ダウンロード
pnpm install    # → Corepack が pnpm@9.1.0 を使用

# 別のパッケージマネージャーを使おうとするとエラー
npm install     # → Error: This project is configured to use pnpm

# packageManager フィールドの設定
corepack use pnpm@9.1.0     # package.json に packageManager を設定
corepack use yarn@4.1.0

9. 高度なトピック

9.1 依存関係のオーバーライドとパッチ

各パッケージマネージャーは、依存関係ツリー内のパッケージバージョンを強制的に変更する機能を提供している。

npm: overrides

{
  "overrides": {
    "semver": ">=7.5.4",
    "lodash": "4.17.21",
    "package-a": {
      "lodash": "4.17.20"
    },
    "got": "$got"
  }
}

yarn Berry: resolutions

{
  "resolutions": {
    "semver": ">=7.5.4",
    "lodash": "4.17.21",
    "package-a/lodash": "4.17.20",
    "@types/node": "20.10.0"
  }
}

pnpm: overrides + pnpm.peerDependencyRules

{
  "pnpm": {
    "overrides": {
      "semver": ">=7.5.4",
      "lodash": "4.17.21",
      "package-a>lodash": "4.17.20"
    },
    "peerDependencyRules": {
      "ignoreMissing": ["@babel/*"],
      "allowAny": ["eslint"],
      "allowedVersions": {
        "react": "18"
      }
    },
    "allowedDeprecatedVersions": {
      "express": "4"
    },
    "patchedDependencies": {
      "some-package@1.0.0": "patches/some-package@1.0.0.patch"
    }
  }
}

9.2 パッチの適用

# yarn Berry のパッチ機能
yarn patch lodash                     # パッチ用の一時ディレクトリを作成
# ... ファイルを編集 ...
yarn patch-commit -s /tmp/xfs-abc123  # パッチをコミット
# → .yarn/patches/lodash-npm-4.17.21-abc123.patch が作成される

# pnpm のパッチ機能
pnpm patch lodash@4.17.21            # パッチ用ディレクトリを作成
# ... ファイルを編集 ...
pnpm patch-commit /tmp/abc123        # パッチをコミット
# → patches/lodash@4.17.21.patch が作成される

# Bun のパッチ機能 (v1.1+)
bun patch lodash                     # パッチ用ディレクトリを作成
# ... ファイルを編集 ...
bun patch --commit /tmp/abc123       # パッチをコミット

# npm では patch-package を使用 (サードパーティ)
npx patch-package lodash             # node_modules内の変更をパッチとして保存
# → patches/lodash+4.17.21.patch が作成される

9.3 セキュリティのベストプラクティス

# npm のセキュリティ対策
npm audit                              # 脆弱性スキャン
npm audit fix                          # 自動修正
npm audit --omit=dev                   # 本番依存のみスキャン
npm config set ignore-scripts true     # 全体的にスクリプト無効化

# pnpm のセキュリティ対策
pnpm audit                             # 脆弱性スキャン
pnpm audit --fix                       # 自動修正
# pnpm はデフォルトで phantom dependencies を防止

# yarn Berry のセキュリティ対策
yarn npm audit                         # 脆弱性スキャン
yarn npm audit --all                   # 全依存関係をスキャン
yarn npm audit --recursive             # 再帰的にスキャン
// package.json - セキュリティ関連の設定
{
  "scripts": {
    "preinstall": "npx only-allow pnpm",
    "prepare": "husky install",
    "audit:ci": "pnpm audit --audit-level=high"
  },
  "engines": {
    "node": ">=18.0.0"
  }
}

9.4 パッケージの公開

# npm レジストリへのパッケージ公開

# ログイン
npm login
npm login --scope=@mycompany --registry=https://npm.pkg.github.com

# 公開前のチェック
npm pack --dry-run                     # パッケージに含まれるファイルを確認
npm publish --dry-run                  # 公開のシミュレーション

# 公開
npm publish                            # 公開
npm publish --access public            # スコープ付きパッケージをpublicに公開
npm publish --tag beta                 # betaタグで公開

# バージョン管理
npm version patch                      # パッチバージョンアップ (1.0.0 → 1.0.1)
npm version minor                      # マイナーバージョンアップ (1.0.0 → 1.1.0)
npm version major                      # メジャーバージョンアップ (1.0.0 → 2.0.0)
npm version prerelease --preid=beta    # プレリリース (1.0.0 → 1.0.1-beta.0)

# 非推奨化
npm deprecate my-package@"< 2.0.0" "Version 1.x is no longer supported"

# 公開取り消し (72時間以内)
npm unpublish my-package@1.0.0

9.5 モノレポツールとの連携

Turborepo との連携

// turbo.json - Turborepo の設定
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**"],
      "cache": true
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"],
      "cache": true
    },
    "lint": {
      "cache": true
    },
    "dev": {
      "persistent": true,
      "cache": false
    }
  }
}
# Turborepo + pnpm の使用例
pnpm dlx turbo run build            # 全ワークスペースのビルド (キャッシュ活用)
pnpm dlx turbo run test --filter=@mycompany/core  # 特定パッケージのテスト
pnpm dlx turbo run build --dry-run  # ビルドグラフの確認

Nx との連携

// nx.json
{
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"],
      "cache": true
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
      "cache": true
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": ["default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)"],
    "sharedGlobals": []
  }
}

9.6 マイグレーションガイド

npm → pnpm への移行

# Step 1: pnpmのインストール
corepack enable
corepack prepare pnpm@9 --activate

# Step 2: ロックファイルの変換
pnpm import                           # package-lock.json から pnpm-lock.yaml を生成

# Step 3: node_modulesの削除と再インストール
rm -rf node_modules
pnpm install

# Step 4: package.json の更新
# packageManager フィールドを追加
{
  "packageManager": "pnpm@9.1.0",
  "scripts": {
    "preinstall": "npx only-allow pnpm"
  }
}
# Step 5: ワークスペースの移行 (モノレポの場合)
# pnpm-workspace.yaml を作成
# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
# Step 6: CI/CDの更新
# npm ci → pnpm install --frozen-lockfile に変更

# Step 7: phantom dependenciesの修正
# pnpm install でエラーが出たら、不足している依存関係を package.json に追加
pnpm install
# ERROR: Cannot find module 'some-package'
# → package.json に "some-package" を追加して再インストール

npm → yarn Berry への移行

# Step 1: yarnのインストール
corepack enable
yarn set version stable

# Step 2: 設定ファイルの作成
# .yarnrc.yml が自動生成される

# Step 3: ロックファイルの変換
yarn import                           # package-lock.json から yarn.lock を生成

# Step 4: node_modules削除と再インストール
rm -rf node_modules
yarn install

# Step 5: (オプション) PnPモードの設定
# デフォルトでPnPが有効
# node_modules が必要な場合は .yarnrc.yml で設定:
# nodeLinker: node-modules

# Step 6: エディタSDKの設定
yarn dlx @yarnpkg/sdks vscode

# Step 7: .gitignore の更新
# yarn Berry の .gitignore
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Zero-Installsを使用する場合 (yarn.lockとキャッシュをコミット)
# .yarn/cache をコミットに含める

10. パッケージマネージャーの選定ガイド

10.1 プロジェクト規模別の推奨

プロジェクト規模推奨パッケージマネージャー理由
個人プロジェクト / 学習npmNode.jsに同梱、追加インストール不要
小〜中規模チームpnpmディスク効率、厳密な依存関係、高速
大規模モノレポpnpm + Turborepo / yarn Berryワークスペース機能の充実
パフォーマンス最優先Bun圧倒的なインストール速度
エンタープライズpnpm / yarn Berryセキュリティ、再現性、ガバナンス
OSS ライブラリ開発npm / pnpm広い互換性

10.2 選定時の考慮事項

選定フローチャート:

1. チームメンバーの経験は?
   ├─ JavaScript初心者が多い → npm (学習コスト最小)
   └─ 経験者が多い → 次の質問へ

2. ディスク容量やCI/CDコストが気になる?
   ├─ はい → pnpm (CASで大幅削減)
   └─ いいえ → 次の質問へ

3. モノレポ構成?
   ├─ はい、大規模 → pnpm + Turborepo or yarn Berry
   ├─ はい、小規模 → pnpm
   └─ いいえ → 次の質問へ

4. インストール速度が最重要?
   ├─ はい → Bun
   └─ いいえ → 次の質問へ

5. 厳密な依存関係分離が必要?
   ├─ はい → pnpm (デフォルト) or yarn Berry (PnP)
   └─ いいえ → npm

11. 今後の展望

11.1 各パッケージマネージャーの動向

  • npm: Node.jsとの統合をさらに深化。セキュリティ機能の強化 (Provenance, Signatures) と、パフォーマンスの継続的改善
  • yarn Berry: PnPエコシステムの拡大、Constraints APIの進化、エディタ統合の改善
  • pnpm: カタログ機能の拡充、パフォーマンスの最適化、CI/CDワークフローの改善
  • Bun: Node.js APIの互換性向上、Windows対応の強化、バンドラー・テストランナーとの統合深化

11.2 共通トレンド

  1. セキュリティの強化: Supply Chain Attack への対策としてのパッケージ署名、来歴追跡、依存関係の厳密化
  2. パフォーマンスの追求: ネイティブ実装 (Rust, Zig) による高速化
  3. モノレポの標準化: ワークスペース機能の充実と外部ツールとの連携
  4. 決定的ビルドの保証: ロックファイルの改善と再現性の向上
  5. 開発者体験の向上: エラーメッセージの改善、対話型ツールの充実

まとめ

JavaScriptのパッケージマネージャーは、単なる依存関係管理ツールから、開発ワークフロー全体を支えるプラットフォームへと進化してきた。

パッケージマネージャー一言まとめ
npmデファクトスタンダード。追加設定不要で始められる万人向けツール
yarn BerryPnPによる革新的アプローチ。大規模プロジェクトでの厳密な管理に強い
pnpm効率性と厳密性のバランスが最も優れた現代的な選択肢
Bun圧倒的な速度を武器にしたオールインワンの次世代ツール

プロジェクトの要件、チームの技術力、インフラストラクチャの制約を総合的に評価し、最適なパッケージマネージャーを選定することが重要である。また、Corepack を活用することで、チーム全体でパッケージマネージャーのバージョンを統一し、一貫した開発環境を維持することが推奨される。