⚙️
--frozen-lockfileで防ぐ、yarn installの破壊的変更
概要
久しく全体的にモジュールのバージョンを見直していた際に、開発用のDocker環境ではビルドが成功するのに、CI/CD環境では失敗するという問題に直面しました。
原因は、CI/CD環境でyarn installが実行された際、間接的な依存モジュールが意図せず更新され、開発環境のキャッシュとバージョンに差異が生まれたことでした。
古いCI/CDパイプラインだったため、依存関係を固定する設定が漏れていたのが直接の原因です。
現象:特定環境でのみビルドが失敗
- Docker コンテナでビルドは成功
- GitHub Actions での CI/CD では突然以下の TypeScript ビルドエラーが発生
error TS2769: No overload matches this call.
Argument of type '{ expiresIn: string; algorithm: "RS256"; }' is not assignable to parameter of 'SignOptions'.
Types of property 'expiresIn' are incompatible.
Type 'string' is not assignable to type 'number | StringValue | undefined'.
- ローカル環境で
node_modulesを削除しクリーンビルドした際も同じエラーが再現。
→ 環境間の依存関係の差異が原因。
調査
1. 型定義の変更
ビルドが成功する環境と失敗する環境とで、インストールされている@types/jsonwebtokenのバージョンが異なっていました。
- v9.0.7 (キャッシュ環境):
expiresIn?: string | number; - v9.0.10 (クリーン環境):
expiresIn?: StringValue | number;
v9.0.7 → v9.0.10 は PATCH でしたが、string を許容しなくなる変更が含まれていました。
2. 依存関係の解決経緯
yarn why @types/jsonwebtokenで依存関係を追跡すると、firebase-adminから間接的にインストールされていることが分かりました。
firebase-admin ^12.0.0
└─ jwks-rsa ^3.1.0 → 3.2.0 (MINOR 更新)
└─ @types/jsonwebtoken ^9.0.2 → ^9.0.4 (依存関係変更)
└─ 実際の解決: 9.0.7 → 9.0.10
package.json のバージョン指定が ^ だったため、キャッシュの無いクリーン環境で ^9.0.4 の範囲内で最新の 9.0.10 が自動的にインストールされていました。
対策
今回の問題の根本的な対策は、ビルド環境ごとの依存関係を完全に一致させることです。
CI/CD でパッケージをインストールする際は、最低限yarn install --frozen-lockfile コマンド(npmの場合はnpm ci)を使用することが大事だと、再認識しました。
Discussion