Skip to main content

第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)

さらに、公式例ではこういう戦い方をします👇

  1. ロックファイル(+必要なら workspace 設定)だけを先にコピー
  2. pnpm fetch で依存を“先に回収”
  3. その後にソース全体を追加して
  4. 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"]

ポイントはここ👇

  • pnpm fetch はロックファイルから仮想ストアへ回収(manifest無視)(pnpm)
  • --offlineストアに無いものがあれば失敗(=“キャッシュの穴”がすぐ分かる)(pnpm)

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)版:-rpnpm-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) よくある落とし穴(ここで事故る😇)🧨

  1. ロックファイルが変わったら当然fetch層も壊れる → でもそれが正しい。依存が変わった証拠だよ👍

  2. --prod を付け忘れると、開発依存まで全部取って遅い&重い pnpm fetch --prod / pnpm install --prod は公式例にも登場します。(pnpm)

  3. --offline で失敗する → ストアに必要なパッケージが無い。fetch が効いてないか、キャッシュが共有されてない。 --offline は “ストアだけ”で、無ければ失敗が仕様です。(pnpm)

  4. private registry(社内npmなど)で認証が必要なのに .npmrc を入れてない 認証系は .npmrc が扱う、とpnpm側でも説明されています。(pnpm) → private依存があるなら、pnpm fetch の前に .npmrc をCOPYする設計にする(ただし秘密情報の扱いは別章でやるやつ🔥)

  5. patchesを使ってるのに、fetch前にCOPYしてない 公式例でも「パッチがあるならfetch前に含める」と書かれています。(pnpm)

  6. モノレポなのに pnpm-workspace.yaml を入れてない → fetchやinstallの解決がズレてハマる可能性大😵‍💫(公式例でもworkspaceファイルをCOPYしています)(pnpm)

  7. 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 --prod
  • pnpm 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 fetchDockerビルド改善のために設計されたコマンドで、ロックファイルだけから依存を先に集める(pnpm)
  • そのあと pnpm install --offline でネットを切って高速化(無ければ失敗=原因が見える)(pnpm)
  • BuildKitの --mount=type=cache と組み合わせると、ビルド間でストアが使い回せてさらに速い(Docker Documentation)

次の章(第15章)では、**「pnpmじゃなくても cache mount の考え方は同じ」**って話に進められるよ😊🧠 もし今のDockerfileを貼ってくれたら、この第14章の型に合わせて“あなたのプロジェクト用”に最適化案をそのまま作ることもできるよ🔥📦