Skip to main content

第10章:pnpmにすると何が速い?どう効く?🏎️📦✨(Dockerで“真価”が出る話)

この章は「pnpmって速いらしいけど、何が速いの?」「Dockerだとどう得するの?」を“腹落ち”させる回だよ😆 結論から言うと、pnpmは **依存関係を“共有ストアに貯めて再利用”**する設計で、Dockerではそれを BuildKitのキャッシュマウントで活かすと爆速になる🔥 (pnpm.io)


✅ この章で学ぶこと(ゴール)🎯

  • pnpmが速い理由(共有ストア+ハードリンク)が説明できる🙂 (pnpm.io)
  • Dockerビルドでの「pnpmの効かせ方」(/pnpm/store をキャッシュ)が分かる🐳⚡️ (pnpm.io)
  • 移行時の“影響範囲”をチェックして、事故らず切り替えられる🧯📝

🧠 図解:pnpmは「共有ストア」と「リンク」で速い📚⚡️

pnpmのざっくり世界観はこれ👇

(1) 共有ストア(content-addressable store)
/pnpm/store ← いろんなプロジェクトで共通に使い回す“倉庫”📦

(2) 各プロジェクトの node_modules は…
倉庫の中身を「リンク」で組み立てる(コピーしまくりじゃない)🔗

pnpmの node_modules は、シンボリックリンクで構造を作りつつ、実ファイルは 共有ストアへのハードリンクとして配置される…という作りになってるよ。だから “同じ依存” が多いほど効いてくる💪 (pnpm.io)


🚀 Dockerでpnpmが強い理由:BuildKitのキャッシュと相性が良すぎる

Dockerビルドが遅くなる大きな原因の1つが「依存ダウンロードを毎回やる」問題😇 BuildKitには RUN --mount=type=cache という機能があって、ビルド中に使うキャッシュ領域を永続化できる。つまり…

  • pnpmの共有ストア(例:/pnpm/store)を
  • BuildKitの cache mount に載せる → 依存が再利用されて、再ビルドが一気に軽くなる🎉 (Docker Documentation)

🛠️ 手順:Dockerで“効く”pnpmの基本形(最短レシピ)🍳🐳

pnpm公式の「Dockerでの推奨形」がまさにこれ。ポイントは2つ👇

  1. corepack enable でpnpmを用意(Nodeに同梱される範囲なら便利)
  2. --mount=type=cache/pnpm/store をキャッシュする (pnpm.io)

例:依存インストールをキャッシュするDockerfile(抜粋)

FROM node:20-slim AS base

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

WORKDIR /app

## 依存だけ先に入れる(変更が少ないものを先に)📌
COPY package.json pnpm-lock.yaml ./

## pnpmの共有ストアをキャッシュマウントに乗せる🔥
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile

## 最後にソースをコピー(変更が多いものは後ろ)🧱
COPY . .

RUN pnpm run build

💡 ここが“効きどころ”だよ

  • target=/pnpm/store が「倉庫」📦
  • ここがキャッシュに残るから、次のビルドでダウンロードが激減する⚡️ (Docker Documentation)

⚡ もう一段速く:pnpm fetch で“仕込み”してキャッシュ最大化📥✨

pnpmには pnpm fetch という、Dockerビルド改善のために設計されたコマンドがあるよ。 ロックファイルを元に依存を先にストアへ集めておき、後段のinstall/ビルドを軽くする発想🪄 (pnpm.io)

例:fetchを使う考え方(超ざっくり)

  • 先に pnpm-lock.yaml をCOPY
  • pnpm fetch --prod で依存を“倉庫へ集める”
  • その後にソースCOPY&ビルド

これもpnpm公式のDockerページに例があるよ。 (pnpm.io)

😵‍💫 注意:file: 依存があると fetch がややこしくなることがある

ローカルパス参照(file:)を含むと、fetchが“それも含めて”取りに行こうとして旨味が減るケースが報告されてるよ。モノレポやローカルパッケージがある人は要注意⚠️ (GitHub)


📝 pnpmへ切り替える「影響範囲チェックリスト」✅(ミニ設計)

pnpm移行は、速さより先に “揃えるもの” があるよ🙂 チェックはこの順が安全🧯

1) ロックファイルが変わる(超重要)🔒

  • package-lock.jsonpnpm-lock.yaml
  • CI/Dockerでは pnpm install --frozen-lockfile 系を使うとズレを防げる(ズレたら落ちる)💥 (pnpm.io)

2) packageManager(固定)があるとチーム運用が楽📌

Corepackと相性がよく、バージョン差事故が減るよ(できれば入れたい)🧠 ※ただしCorepackの同梱状況はNodeの世代で変わるので、最新系では注意ね。 (GitHub)

3) .npmrc 相当の設定

npmの設定を使ってる人は、pnpmでも同等設定が必要なことがある(レジストリ、proxy、strict-ssl等)🌐

4) “たまに壊れる”系(依存の貼り方の違い)

pnpmはリンク構造なので、古い前提のツールがまれに困ることがある😇 (例:node_modulesを直書き前提のスクリプトなど)


🧪 ミニ演習:pnpmの速さを“数字で体験”しよう📊⏱️

演習1:ローカルで install を計測(Windowsならこれ)🪟

PowerShellでサクッと👇

Measure-Command { pnpm install }

比較したいなら、切り替え前に npm install も計測してメモ📝 そして「2回目のinstall」が速いかも見てみてね(共有ストアの旨味)📦⚡️ (pnpm.io)

演習2:Dockerビルドで“キャッシュの効き”を体感🐳

1回目と2回目のビルド時間を比べよう。

docker build -t speed-test .
docker build -t speed-test .

BuildKitのキャッシュマウントが効くと、2回目が気持ちよく短くなるはず😆 (Docker Documentation)


😵‍💫 よくある落とし穴(ここで詰まりやすい)🧯

1) Dockerfileで COPY . . が早すぎる📦💥

ソース変更のたびに依存レイヤが壊れて「毎回インストール」になりがち😇 → package.jsonpnpm-lock.yaml を先にCOPYして依存、ソースは最後!が鉄板🧱

2) --frozen-lockfile で落ちる(でも正しい)✅💥

落ちるのは「ロックとpackage.jsonがズレてるよ」の合図。CIではむしろ守り神👼 (Stack Overflow)

3) Corepackが見つからない/挙動が違う🧩

Nodeの世代でCorepackの同梱条件が変わるので、DockerイメージのNodeバージョンを変えたら要チェック👀 (GitHub)

4) file: 依存やモノレポで pnpm fetch が効きにくい🎒

“ローカルの中身”も絡むと、fetchの美味しさが減ることがある(構成次第)⚠️ (GitHub)


🤖 AI活用:pnpm移行&Docker高速化を“雑に相談してOK”にするプロンプト集✨

コピペでどうぞ😆(Copilot/Codex向け)

1) 影響範囲チェックを作らせる📝

このリポジトリを npm から pnpm に移行したい。
想定される影響範囲チェックリストを、(1)ローカル開発 (2)Dockerビルド (3)CI の3カテゴリで作って。
node_modulesの構造差(symlink/hardlink)で起きがちな注意点も入れて。

2) Dockerfileを“キャッシュが効く形”に直させる🐳⚡️

このDockerfileを、pnpmの公式推奨に近い形で高速化して。
条件:
- BuildKitの RUN --mount=type=cache を使う
- /pnpm/store をキャッシュ
- package.json と pnpm-lock.yaml を先にCOPYして依存をキャッシュ温存
修正後のDockerfile全文と、改善点の説明をください。

3) fetchを使うべきか判断させる🧠

このプロジェクト構成(モノレポ/ローカルfile依存の有無)で pnpm fetch を使うべき?
メリット/デメリットと、使う場合のDockerfile例を2案ください。

✅ まとめ:第10章の“持ち帰り”🎁

  • pnpmは「共有ストア+リンク」で、同じ依存の再利用が効く📦🔗 (pnpm.io)
  • Dockerでは RUN --mount=type=cache/pnpm/store をキャッシュすると強い🐳⚡️ (Docker Documentation)
  • pnpm fetch はDockerビルド改善のために用意されてるけど、file:依存があると注意⚠️ (pnpm.io)

次の章(第11章)は **Corepackまわりの“混乱しがちな最新版事情”**をスッキリ整理して、「ローカルもDockerもCIも同じpnpmバージョン」へ寄せる作戦に入るよ🧩🔒✨