📄
概念 📚 fullstack-curriculum 手を動かす STEP 4

パッケージ管理(pnpm workspace)

pnpm・package.json・依存関係の仕組みを理解し、pnpm workspaceを使ったモノリポ構成を使いこなす

STEP 4

パッケージ管理と開発の土台をそろえる

手を動かす

pnpm workspace と依存関係の基本を押さえ、以後の React / Hono 実装の土台を整える段階。

この STEP で作るもの

  • pnpm workspace を前提にした開発リポジトリの理解

この STEP でできるようになること

  • dependencies と devDependencies の違いを説明できる
  • pnpm の基本コマンドで依存関係を扱える
  • モノリポ構成の土台を理解できる

この章で手を動かすこと

  • pnpm の基本コマンドを使える
  • workspace と package.json の役割を説明できる

次に活きる章

Webアプリアーキテクチャ全体像 Reactコンポーネント設計の基礎

pnpmはNode.jsのパッケージマネージャーで、Pythonの pip に相当します。このカリキュラムでは npm の代わりに pnpm を使います。理由は2つで、インストールが高速・ディスク使用量が少ないこと、そして workspace(モノリポ)機能が標準で使えることです。

コラム: lockfile はなぜ commit するのか

pnpm-lock.yaml は「いま本当に入った依存関係の正確な組み合わせ」を固定するファイルです。package.json だけだと、^~ の範囲で後日別バージョンが入る可能性があり、昨日動いたものが今日だけ壊れることがあります。

lockfile を commit しておけば、チーム全員と CI が同じ依存関係を再現できます。ライブラリ更新で不具合が起きたときも、「コード変更」なのか「依存変更」なのかを切り分けやすくなります。

概念リンク

書籍

  • 『フロントエンドの知識地図』: 依存管理やビルド周辺を広く俯瞰できる
  • 『JavaScript Primer』: npm エコシステムの基本理解を補強しやすい

pnpm の基本コマンド

Terminal window
pnpm install # package.jsonの全依存関係をインストール
pnpm add react # reactを追加
pnpm add -D typescript # TypeScriptをdevDependenciesに追加
pnpm remove lodash # パッケージを削除
pnpm dev # scripts.devを実行
pnpm build # scripts.buildを実行
pnpm test # テストを実行

npm の代わりに pnpm と書くだけで、ほぼ同じように使えます。

package.json の構造

{
"name": "api",
"version": "0.1.0",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc -p tsconfig.build.json",
"typecheck": "tsc --noEmit",
"db:push": "drizzle-kit push"
},
"dependencies": {
"hono": "^4.9.0"
},
"devDependencies": {
"typescript": "^5.9.0",
"tsx": "^4.19.2"
}
}

dependencies: アプリの実行に必要なパッケージ
devDependencies: 開発・ビルド時のみ使うパッケージ(TypeScript等)
scripts: pnpm dev のように呼び出せるコマンドの定義

pnpm workspace(モノリポ)

このカリキュラムのリポジトリは pnpm workspace を使ったモノリポ構成になっています。

fullstack_typescript_curriculum/
├── pnpm-workspace.yaml workspaceの設定
├── package.json ルートのパッケージ設定(全体のスクリプト)
├── web/ フロントエンド(React + Vite)
│ └── package.json
└── api/ バックエンド(Hono)
└── package.json
pnpm-workspace.yaml
packages:
- "web"
- "api"

1つのリポジトリに web/api/ という2つの独立したパッケージが共存しています。これが**モノリポ(monorepo)**と呼ばれる構成です。

ルートからの一括操作

ルートディレクトリから web/api/ の両方を操作できます。

Terminal window
# ルートで pnpm dev を実行すると web と api が同時に起動
pnpm dev
# 特定のワークスペースだけ操作する
pnpm --filter api add hono
pnpm --filter web add react-router-dom
# 全ワークスペースに対して実行
pnpm -r typecheck # web と api 両方で型チェック

node_modules とロックファイル

fullstack_typescript_curriculum/
├── node_modules/ ← pnpm が一元管理(gitignore する)
├── pnpm-lock.yaml ← バージョンのロックファイル(gitに含める)
├── web/
│ └── node_modules → ../../node_modules(シンボリックリンク)
└── api/
└── node_modules → ../../node_modules(シンボリックリンク)

pnpm はパッケージを一箇所(~/.pnpm-store)に保存し、シンボリックリンクで参照します。同じパッケージを複数プロジェクトで使っても1回しかダウンロードしません。

pnpm-lock.yaml はインストールした各パッケージの正確なバージョンを記録します。これをGitにコミットすることでチーム全員が同じバージョンを使えることが保証されます。

セマンティックバージョニング

バージョン番号 4.9.0メジャー.マイナー.パッチ の意味です。

  • パッチ(4.9.0 → 4.9.1): バグ修正のみ
  • マイナー(4.9.0 → 4.10.0): 新機能追加、後方互換あり
  • メジャー(4.9.0 → 5.0.0): 破壊的変更、移行作業が必要

^4.9.0(キャレット): メジャーを固定、マイナー・パッチは最新を許可

参考リソース


確認クイズ

Q1. pnpm が npm より優れている点を2つ挙げてください。

正解: インストールが高速でディスク使用量が少ない、workspace(モノリポ)機能が標準で使える

解説: pnpm はパッケージをグローバルストア(~/.pnpm-store)に一度だけ保存し、各プロジェクトからシンボリックリンクで参照します。そのためnpmのように同じパッケージを何度もダウンロードせず、ディスクを節約できます。

Q2. pnpm add -D typescript を実行すると、package.json のどのフィールドにtypescriptが追加されますか。
  • A. dependencies
  • B. devDependencies
  • C. scripts
  • D. peerDependencies

正解: B

解説: -D フラグは devDependencies への追加を指定します。TypeScriptはコンパイル時のみ使用し、実行環境では不要なため devDependencies に入れるのが正しいです。本番サーバーで不要なパッケージを dependencies に入れるとデプロイパッケージが肥大化します。

Q3. pnpm-workspace.yaml はどのような役割を持つファイルですか。

正解: モノリポ内のどのディレクトリをワークスペース(個別パッケージ)として認識するかを定義するファイルです。

解説: packages: フィールドにディレクトリ名を列挙することで、ルートの pnpm が各パッケージを認識できるようになります。これにより --filter による個別操作や -r による全体一括操作が可能になります。

Q4. モノリポ(monorepo)とはどのような構成を指しますか。

正解: 1つのリポジトリに複数の独立したパッケージ(例:web と api)が共存する構成です。

解説: モノリポにすることで、フロントエンドとバックエンドを同じリポジトリで管理でき、依存関係の共有やルートからの一括操作が容易になります。pnpm workspace はこの構成を低コストで実現します。

Q5. pnpm --filter api add hono コマンドは何をしますか。

正解: api ワークスペースだけに hono パッケージを追加します。

解説: --filter オプションを使うと、ルートディレクトリにいながら特定のワークスペースのみを対象に操作できます。web/ に移動して pnpm add するのと同等ですが、ルートから統一的に操作できる利点があります。

Q6. pnpm -r typecheck コマンドが実行すること、および -r フラグの意味を答えてください。

正解: -r は全ワークスペース(recursive)を対象にするフラグです。webapi 両方の scripts.typecheck を実行します。

解説: -r フラグを使うと pnpm-workspace.yaml で定義された全パッケージに対して同じコマンドを一斉実行できます。CIで全パッケージの型チェックやテストを実行するときに便利です。

Q7. pnpm において node_modules はどのように管理されますか。
  • A. 各パッケージに個別に保存される
  • B. グローバルストアに1か所保存しシンボリックリンクで参照する
  • C. クラウドに保存される
  • D. package.json に埋め込まれる

正解: B

解説: pnpm は ~/.pnpm-store にパッケージを一元保存し、各プロジェクトの node_modules からシンボリックリンクで参照します。同一パッケージを複数プロジェクトで使っても実体は1つのためディスク節約になります。

Q8. pnpm-lock.yaml をGitにコミットすべき理由を答えてください。

正解: チーム全員が同じバージョンのパッケージを使えることを保証するためです。

解説: ロックファイルがなければ pnpm install の実行タイミングによってインストールされるパッケージのバージョンが異なる可能性があります。ロックファイルをコミットすることで「自分のPCでは動くが他の人の環境では動かない」問題を防げます。

Q9. バージョン ^4.9.0 のキャレット(^)は何を意味しますか。

正解: メジャーバージョンを固定し、マイナーとパッチは最新を許可します。つまり 4.x.x の最新が許可されます(5.0.0 は対象外)。

解説: セマンティックバージョニングではメジャー変更が破壊的変更を意味するため、キャレットを使うことで安全な範囲で自動更新できます。ただし依存関係の完全固定が必要な場合はロックファイルと組み合わせて使います。

Q10. 4.9.0 → 5.0.0 のようなメジャーバージョンアップが行われる場合、何が起きる可能性がありますか。

正解: 破壊的変更(breaking change)が含まれており、既存のコードが動かなくなる可能性があります。移行作業が必要になります。

解説: セマンティックバージョニングの規約では、メジャーバージョンアップは後方互換性のない変更を含むことを示します。APIの引数変更・関数の廃止・動作の変更などが含まれるため、アップグレード前にリリースノートやマイグレーションガイドを確認する必要があります。

この章で手を動かすときの確認

この章は 導入編 の STEP 4にある 「手を動かす」 の章です。本文を読み終えたあと、次の観点だけ確認すると次へ進みやすくなります。

この章で確認すること:

  • pnpm の基本コマンドを使える
  • workspace と package.json の役割を説明できる

次に活きる章:

  • Webアプリアーキテクチャ全体像
  • Reactコンポーネント設計の基礎

補助参照: