第14章:pnpmの裏技:pnpm fetchで“準備だけ”して速くする 📥⚡️
この章はひとことで言うと、**「依存のダウンロードを“先に済ませて”、あとを爆速にする」**テクです😆✨ 特にDockerは、ちょっとした変更でキャッシュが壊れがちなので、ここを押さえると体感がガラッと変わります🔥
1) まずイメージしてほしい“遅さの正体”🐢💭
Dockerビルドが遅いとき、だいたい犯人はこれ👇
pnpm installの 依存ダウンロード(ネット) が毎回走るpackage.jsonのちょっとした変更(バージョン、scripts、設定など)で、依存インストール層のキャッシュが壊れる
そこで登場するのが pnpm fetch 🎉
pnpm fetch は **「ロックファイル(pnpm-lock.yaml)だけを見て、必要なパッケージを先に仮想ストアへ集める」**コマンドです。package.json は無視します。(pnpm)
2) pnpm fetchがDocker向きな理由(超重要)🧠✨
pnpm fetch は、公式に **「Dockerイメージのビルド改善のためのコマンド」**として説明されています。(pnpm)
さらに、公式例ではこういう戦い方をします👇
- ロックファイル(+必要なら workspace 設定)だけを先にコピー
pnpm fetchで依存を“先に回収”- その後にソース全体を追加して
pnpm install --offlineで ネット無しでインストール(=速い)(pnpm)
これ、何が嬉しいかというと…
✅ ソースをいじっても、ロックファイルが変わらなければ“fetch層”がキャッシュされる
✅ package.json をちょい変更しても、fetchのキャッシュが守られやすい(ロックファイルが同じなら)(pnpm)
✅ モノレポでもDockerfileが破綻しにくい(サブパッケージのpackage.jsonを列挙コピーする苦行から解放)(pnpm)
3) ざっくり図解:fetchを挟むと何が変わる?🗺️✨
**普通の流れ(遅くなりがち)**😵💫
- COPY(いろいろ)
pnpm install(毎回ネット&重い)
fetchを入れる流れ(速くしやすい)⚡️
- COPY(ロックファイルだけ)
pnpm fetch(依存を先に回収)- ADD(ソース全部)
pnpm install --offline(ネット禁止で高速化)(pnpm)
4) 実践レシピ:まずは単体プロジェクト版 🍳✨
ここでは例として node:22 系のイメージを使います(Node公式イメージ例で node:22 が使われています)(GitHub)
※バージョンはプロジェクトの方針で固定してね👍
## syntax=docker/dockerfile:1
FROM node:22-slim AS base
WORKDIR /app
## pnpm を使えるように(Corepack)
RUN corepack enable
## ① まずは「ロックファイルだけ」
COPY pnpm-lock.yaml ./
## workspaceを使ってるなら(モノレポ/workspace構成)
## COPY pnpm-workspace.yaml ./
## パッチを使ってるなら(ある人だけ)
## COPY patches patches
## ② 依存を“先に回収”(package.json は見ない)
RUN pnpm fetch --prod
## ③ ソース全部を入れる
COPY . .
## ④ ネット禁止でインストール(速い&失敗が分かりやすい)
RUN pnpm install --offline --prod
CMD ["node", "dist/index.js"]
ポイントはここ👇
5) さらに速くする:BuildKitのキャッシュマウント合体 💥🚀
これをやると、ビルド間でpnpmのストアを使い回せるので、再ビルドがかなり軽くなります🔥 BuildKitのキャッシュマウントは「ビルド中に使う永続キャッシュ置き場」を指定でき、同じキャッシュを次回ビルドでも再利用できます。(Docker Documentation)
pnpm公式も、Dockerで BuildKit cache mount を推奨していて、例では /pnpm/store をキャッシュ対象にしています。(pnpm)
## syntax=docker/dockerfile:1
FROM node:22-slim
WORKDIR /app
RUN corepack enable
## pnpmのストアを分かりやすい場所に
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
COPY pnpm-lock.yaml ./
## COPY pnpm-workspace.yaml ./
## COPY patches patches
## ★ここがキモ:pnpmのストアをキャッシュマウント
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm fetch --prod
COPY . .
## ★install側でも同じキャッシュを使う
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --offline --prod
💡もし RUN --mount=type=cache ... がエラーになるなら、BuildKitが無効になってる可能性あり。Dockerのキャッシュ最適化はBuildKit前提で説明されています。(Docker Documentation)
6) モノレポ(workspace)版:-r と pnpm-workspace.yaml 🧩🏢
公式のpnpm fetchページでは、モノレポでも pnpm-workspace.yaml を一緒に置いて、pnpm install -r --offline の形が紹介されています。(pnpm)
FROM node:22-slim
WORKDIR /app
RUN corepack enable
COPY pnpm-lock.yaml pnpm-workspace.yaml ./
## COPY patches patches
RUN pnpm fetch --prod
COPY . .
## -r でワークスペース全体へ(必要な場合)
RUN pnpm install -r --offline --prod
7) よくある落とし穴(ここで事故る😇)🧨
-
ロックファイルが変わったら当然fetch層も壊れる → でもそれが正しい。依存が変わった証拠だよ👍
-
--prodを付け忘れると、開発依存まで全部取って遅い&重いpnpm fetch --prod/pnpm install --prodは公式例にも登場します。(pnpm) -
--offlineで失敗する → ストアに必要なパッケージが無い。fetchが効いてないか、キャッシュが共有されてない。--offlineは “ストアだけ”で、無ければ失敗が仕様です。(pnpm) -
private registry(社内npmなど)で認証が必要なのに
.npmrcを入れてない 認証系は.npmrcが扱う、とpnpm側でも説明されています。(pnpm) → private依存があるなら、pnpm fetchの前に.npmrcをCOPYする設計にする(ただし秘密情報の扱いは別章でやるやつ🔥) -
patchesを使ってるのに、fetch前にCOPYしてない 公式例でも「パッチがあるならfetch前に含める」と書かれています。(pnpm)
-
モノレポなのに
pnpm-workspace.yamlを入れてない → fetchやinstallの解決がズレてハマる可能性大😵💫(公式例でもworkspaceファイルをCOPYしています)(pnpm) -
file:依存(ローカルパス参照)があるpnpm fetchはDocker最適化でよく使われる一方で、file:をどう扱うかの議論も出ています(2026年1月のIssue)。(GitHub) → こういう構成は、Dockerfile設計をちょい工夫する必要あり(“完全にロックファイルだけ”で済まないケースがある)
8) 🧪ミニ演習:Windowsで「速くなった!」を数字で体験しよう 📊✨
Step A: 計測用コマンド(PowerShell)⏱️
Measure-Command { docker build -t speedtest:before . } | Select-Object TotalSeconds
Step B: Dockerfileを「fetch版」に変更🛠️
pnpm fetch --prodpnpm install --offline --prod- できれば
--mount=type=cacheも入れる(BuildKit)
Step C: もう一回計測🔥
Measure-Command { docker build -t speedtest:after . } | Select-Object TotalSeconds
観察ポイント👀✨
- 1回目(キャッシュ無し):そこそこ時間かかる
- 2回目(変更なし):かなり速くなるはず
- ソースだけ変更:fetch層が生きてると、依存ダウンロード地獄が消える😍
9) 🤖AI活用(Copilot / Codex向け)プロンプト例🪄
① Dockerfileレビュー(キャッシュの壊れポイント特定)🕵️♂️
以下のDockerfileで、キャッシュが壊れやすい箇所を3つ指摘して。
pnpm fetch / pnpm install --offline を使った改善案も2パターン出して。
(BuildKit cache mount も使える前提)
---
<ここにDockerfileを貼る>
② “速いのに壊れない”構成へリライト✍️⚡️
このプロジェクトはpnpmで、Dockerビルドが遅いです。
pnpm fetchを使って「ロックファイルが変わらない限り依存DLを再実行しない」Dockerfileに書き換えて。
また、pnpm storeをBuildKit cache mountで使い回す形にして。
---
<package.json / pnpm-lock.yaml の概要 or Dockerfile>
③ --offline が失敗したときの診断🔧😵💫
pnpm install --offline --prod がDockerビルド中に失敗します。
原因候補を優先度順に10個出して、確認コマンドと修正方針もセットで教えて。
---
<エラーログを貼る>
10) まとめ:この章の“持ち帰り”🎁🏁
pnpm fetchは Dockerビルド改善のために設計されたコマンドで、ロックファイルだけから依存を先に集める(pnpm)- そのあと
pnpm install --offlineでネットを切って高速化(無ければ失敗=原因が見える)(pnpm) - BuildKitの
--mount=type=cacheと組み合わせると、ビルド間でストアが使い回せてさらに速い(Docker Documentation)
次の章(第15章)では、**「pnpmじゃなくても cache mount の考え方は同じ」**って話に進められるよ😊🧠 もし今のDockerfileを貼ってくれたら、この第14章の型に合わせて“あなたのプロジェクト用”に最適化案をそのまま作ることもできるよ🔥📦