Package Manager
JavaScriptパッケージマネージャー完全ガイド: npm, yarn, pnpm, Bun
はじめに
JavaScriptエコシステムにおいて、パッケージマネージャーは開発ワークフローの根幹を支える重要なツールである。パッケージマネージャーは、外部ライブラリやフレームワークの依存関係を管理し、プロジェクトの構築・配布・共有を効率化する役割を担う。
現代のJavaScript開発では、数百から数千のパッケージに依存するプロジェクトが一般的であり、これらの依存関係を手動で管理することは事実上不可能である。パッケージマネージャーは以下の課題を解決する。
- 依存関係の解決: パッケージ間のバージョン互換性を自動的に解決する
- 再現性の保証: 異なる環境で同一の依存関係ツリーを再現する
- セキュリティ管理: 脆弱性のあるパッケージを検出・更新する
- ワークスペース管理: モノレポ構成でのマルチパッケージ管理を支援する
- スクリプト実行: ビルド・テスト・デプロイなどのタスクを統一的に管理する
本稿では、JavaScript/Node.jsエコシステムにおける主要な4つのパッケージマネージャー — npm、yarn、pnpm、Bun — について、それぞれのアーキテクチャ、特徴、設定方法、ユースケースを包括的に解説する。
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 (バイナリ) |
| 対応OS | macOS, 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 機能比較
| 機能 | npm | yarn Berry | pnpm | Bun |
|---|---|---|---|---|
| デフォルトインストール | Node.js同梱 | Corepack | 別途インストール | 別途インストール |
| ロックファイル | package-lock.json | yarn.lock | pnpm-lock.yaml | bun.lock / bun.lockb |
| ストレージ方式 | フラット | PnP (ZIP) / フラット | CAS + シンボリックリンク | フラット |
| ワークスペース | v7+ | 高度なサポート | フィルタリング充実 | 基本サポート |
| Phantom Dependencies | 発生する | PnPで防止 | デフォルトで防止 | 発生する |
| オフライン対応 | キャッシュ | Zero-Installs | ストア | キャッシュ |
| プラグインシステム | なし | あり | なし | なし |
| セキュリティ監査 | npm audit | yarn npm audit | pnpm audit | 限定的 |
| モノレポツール連携 | 基本 | 高度 | Turborepo, Nx | 基本 |
| パッチ機能 | patch-package | yarn patch | pnpm patch | bun patch |
| ライセンスチェック | サードパーティ | プラグイン | サードパーティ | なし |
7.2 パフォーマンス比較
| 指標 | npm | yarn Berry (PnP) | pnpm | Bun |
|---|---|---|---|---|
| 初回インストール速度 | 遅い | 中程度 | 速い | 最速 |
| キャッシュありインストール | 中程度 | 速い (Zero-Install) | 速い | 最速 |
| ディスク使用量 | 大 | 小 (ZIP圧縮) | 最小 (CAS) | 大 |
| CI/CDパフォーマンス | 中程度 | 速い | 速い | 最速 |
| メモリ使用量 | 中程度 | 中程度 | 低い | 低い |
7.3 エコシステム互換性
| 互換性 | npm | yarn Berry | pnpm | Bun |
|---|---|---|---|---|
| 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 プロジェクト規模別の推奨
| プロジェクト規模 | 推奨パッケージマネージャー | 理由 |
|---|---|---|
| 個人プロジェクト / 学習 | npm | Node.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 共通トレンド
- セキュリティの強化: Supply Chain Attack への対策としてのパッケージ署名、来歴追跡、依存関係の厳密化
- パフォーマンスの追求: ネイティブ実装 (Rust, Zig) による高速化
- モノレポの標準化: ワークスペース機能の充実と外部ツールとの連携
- 決定的ビルドの保証: ロックファイルの改善と再現性の向上
- 開発者体験の向上: エラーメッセージの改善、対話型ツールの充実
まとめ
JavaScriptのパッケージマネージャーは、単なる依存関係管理ツールから、開発ワークフロー全体を支えるプラットフォームへと進化してきた。
| パッケージマネージャー | 一言まとめ |
|---|---|
| npm | デファクトスタンダード。追加設定不要で始められる万人向けツール |
| yarn Berry | PnPによる革新的アプローチ。大規模プロジェクトでの厳密な管理に強い |
| pnpm | 効率性と厳密性のバランスが最も優れた現代的な選択肢 |
| Bun | 圧倒的な速度を武器にしたオールインワンの次世代ツール |
プロジェクトの要件、チームの技術力、インフラストラクチャの制約を総合的に評価し、最適なパッケージマネージャーを選定することが重要である。また、Corepack を活用することで、チーム全体でパッケージマネージャーのバージョンを統一し、一貫した開発環境を維持することが推奨される。