Skip to main content

第09章:依存固定:lockfileを信じる世界 🧷

この章はひとことで言うと、**「本番ビルドが“昨日と同じ結果”になるように固定する」**回だよ😊 ローカルで動いたのに、本番ビルドで突然コケる…😇 その事故の多くは **依存関係(npmパッケージ)**が原因になりがち。そこで登場するのが lockfile(ロックファイル)!🔒✨


この章のゴール 🎯✨

  • ✅ lockfileが何で、なぜ本番で超大事か分かる
  • ✅ CI / Docker build で「依存が勝手に変わらない」状態を作れる
  • ✅ Dockerfileで 依存インストールがキャッシュに乗る順序を組める ⚡
  • npm ci / pnpm install --frozen-lockfile / yarn install --immutable を使い分けできる 🧠

1) lockfileって何?(超ざっくり)🧠🔒

package.json は「だいたいこのへんのバージョン使ってね(例: ^1.2.3)」みたいな 希望 を書く場所📄 一方 lockfile は「実際に入れたのはこれ!このバージョン!これ!」っていう 確定結果のメモ🧾✨

  • npm → package-lock.json(または npm-shrinkwrap.json)📌 (npm ドキュメント)
  • pnpm → pnpm-lock.yaml 📌 (pnpm)
  • Yarn → yarn.lock 📌 (Yarn)

つまり lockfile をコミットしておくと、別のPC / CI / 本番でも “同じ依存” を再現しやすくなる💪✨ これが「そのままデプロイ」では生命線になるよ🫀🔥


2) 本番で死にがちな “依存事故” あるある ☠️💥

あるある①:昨日は通ったのに、今日は落ちた 😭

package.json^ で範囲指定してると、依存が勝手に新しい版にズレることがある👉 で、急に壊れる🫠

あるある②:ローカルはOK、CIだけNG 🤖❌

ローカルの node_modules が残ってて動いてるだけ、みたいなパターン😇 CIは毎回クリーンだから、依存のズレが即バレる。

あるある③:Docker build が遅すぎる 🐢📦

依存インストールが毎回やり直しになる構造だと、ビルドが地獄👹 ここも lockfile と Dockerfile の順番で解決できる!


3) “固定インストール”の正解コマンド ✅🧷

npm の場合:npm ci が本番・CIの基本 👑

npm cilockfileどおりにクリーンインストールする専用コマンド。 ポイントはこれ👇

  • lockfile(package-lock.json等)が必須
  • package.json と lockfile がズレてたら エラーで止まる(勝手に直さない)
  • node_modules があったら 消してから入れ直す
  • lockfileや package.json絶対に書き換えない(凍結)🧊 (npm ドキュメント)

つまり CI で npm ci を回すと、「ズレたら即死」=事故が早期発見できる😆👍 (npm ドキュメント)


pnpm の場合:CIだと “lockfile更新が必要なら失敗” が基本挙動 💥

pnpm はCI環境だと、lockfileが古いとインストールが失敗する(=ズレを許さない)方向になってるよ📌 (pnpm) さらに明示するなら:

  • pnpm install --frozen-lockfile(ズレたらエラー)🧊 (pnpm)

Yarn の場合:--immutable が “lockfile絶対変更しない” の合図 🧊

  • yarn install --immutable(lockfile変更が必要ならエラー) (Yarn)

4) “使うパッケージマネージャを固定”する(Corepack)🧰✨

チームやCIで地味に起きるのがこれ👇 「Aさんはpnpm、Bさんはnpm、CIはYarn」みたいなカオス🤯

そこで Corepack。Nodeに同梱される仕組みで、プロジェクト指定のYarn/pnpmを呼び出せる感じになるよ🪄 (Node.js)

よくある固定方法👇(例)

{
"packageManager": "pnpm@9.0.0"
}

これで「このプロジェクトはpnpmのこのバージョンね」って意思表示になる✍️ Corepack自体の有効化はこういうノリ👇(1回やるやつ)

corepack enable

(Corepackは corepack enable で有効化する流れが公式に説明されてるよ)(Node.js)


5) Dockerfileで “依存キャッシュが効く順番” を作る ⚡🐳

ここ超重要!!🎉 Docker buildが速くなるかどうかは、だいたいこの順番で決まる👇

✅ 鉄板ルール:まず package.json と lockfile だけCOPYする 📦➡️

そして依存インストールを先にやる。 こうすると、アプリのソースを少し変えただけなら依存レイヤーが再利用される

npm 例(ビルド用ステージ)

## 依存だけ先に入れてキャッシュを効かせる
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

この「COPYの順番」が命😇 COPY . . を先にやると、1行でもコードが変わるたびに依存が全部やり直しになりがち💥


6) さらに速くする:BuildKitのキャッシュマウント 🏎️💨

DockerのBuildKitには **“キャッシュ置き場をマウントして再利用する”**仕組みがあるよ📦✨ これを使うと、レイヤーキャッシュが崩れても「落としてきたパッケージ」が再利用されて速い⚡ (Docker Documentation)

npmの例(npmキャッシュを使い回す)

## syntax=docker/dockerfile:1
WORKDIR /app
COPY package.json package-lock.json ./
RUN --mount=type=cache,target=/root/.npm npm ci

Docker公式が “cache mounts” の説明と例を出してるよ📌 (Docker Documentation)


7) pnpm × Dockerの“速いやつ” 🧠⚡

pnpmはDocker向けに、わりと露骨に最適化ルートが用意されてる✌️

  • pnpm fetchlockfileだけで依存を先に集めるのに向いてる(Dockerレイヤーキャッシュと相性◎)(pnpm)
  • その後 --offline でインストールしてネットに行かない構成にできる (pnpm)

ざっくりイメージ👇

WORKDIR /app
COPY pnpm-lock.yaml package.json ./
RUN corepack enable
RUN pnpm fetch
COPY . .
RUN pnpm install --offline

(pnpm公式がDockerでの考え方として pnpm fetch を推してるよ)(pnpm)


8) ハンズオン:依存固定の “事故らない流れ” を体に入れる 💪🧪

Step 1:lockfileを必ずコミットする ✅

  • npmなら package-lock.json
  • pnpmなら pnpm-lock.yaml
  • Yarnなら yarn.lock

Step 2:CI / 本番用コマンドを “固定インストール” にする 🧊

Step 3:Dockerfileを “依存が先にキャッシュされる順番” にする 🐳⚡

  • lockfile + package.json を先にCOPY
  • install
  • その後にソースCOPY

9) つまずきTop5 😵‍💫🧯(最短で直す)

npm ci が「lockfileとpackage.jsonが一致しない」って怒る

👉 それが正常!😆(ズレ検知) 直し方:ローカルで npm install して lockfile を更新→コミット。 (npm ci はズレてもlockfileを更新しない仕様)(npm ドキュメント)

npm ci で peer deps 関連の設定が違ってコケる

👉 lockfile作成時に使った設定(例:--legacy-peer-deps)と同じ設定が必要なことがある。.npmrc をプロジェクトに置いてコミット、みたいな話が公式にもあるよ📌 (npm ドキュメント)

③ Docker build が毎回遅い

👉 DockerfileのCOPY順が原因率高め。依存ファイル先コピーに直す!

④ pnpmでCIだけ失敗する

👉 CIだとlockfileが古いと失敗する方向なので、lockfile更新漏れを疑う(pnpm)

⑤ Yarnで --frozen-lockfile 使って警告が出る

👉 近年は --immutable が推奨になりがち(Yarn公式のinstallに載ってる)(Yarn)


10) 章末チェックリスト ✅📌

  • lockfileをコミットしてる🧷
  • CI/本番は “固定インストール” コマンドにしてる🧊
  • Dockerfileは「依存ファイル→install→ソース」の順になってる🐳
  • さらに速くしたいなら BuildKit の cache mount を検討できる⚡ (Docker Documentation)
  • pnpmなら pnpm fetch を選択肢に入れられる📦 (pnpm)

11) AIに投げるコピペ用プロンプト集 🤖📎

  • 「このリポジトリの package manager(npm/pnpm/yarn)を判定して、CI向けの“lockfile固定インストール”コマンドを1つだけ提案して」
  • 「Dockerfileで依存キャッシュが最大限効くCOPY順に並べ替えて。npm/pnpm/yarnのどれでも破綻しない形で」
  • npm ci が失敗した。package.jsonとlockfileのズレを直す手順を“安全第一”で説明して(余計な自動更新を避けたい)」
  • 「pnpm fetch を使う場合のDockerfileを、最小ステップで書いて」

次の第10章(.dockerignore:速さと安全の地味王 👑🧹)に行く前に、ここで一回だけ言わせて😆 **lockfileは“本番のタイムマシン”**だよ🕰️✨ これがあると「昨日動いた状態」を何回でも召喚できる。強い💪🔥