npm-check-updatesでより賢いパッケージ更新を実現する
依存関係のドリフトはプロジェクトを徐々に破壊します。いくつかの更新をスキップし、さらにいくつかスキップすると、気づけば47個の古いパッケージに直面することになります。その半分には破壊的変更があり、一部にはセキュリティ脆弱性があり、明確な前進の道筋は見えません。npm updateを実行することはロシアンルーレットのように感じられます。一括アップグレードはCIを壊します。安全な選択は何もしないことになりますが、それは全く安全ではありません。
npm-check-updates(ncu)は異なるアプローチを提供します。何を更新するかの決定と、インストールおよびテストの実行を分離するのです。この区別は、ほとんどのチームが認識している以上に重要です。
重要なポイント
- ncuはnode_modulesやロックファイルに触れることなくpackage.jsonのバージョン範囲を変更し、インストールのタイミングを制御できます
--target minorまたは--target patchを使用して、非破壊的な変更のみに更新を制限します--peerフラグは、ピア依存関係の競合を引き起こす更新の提案を防ぎます- 更新をテストした後は、必ずpackage.jsonとpackage-lock.jsonを一緒にコミットしてください
- 脆弱性に対処する際は、npmの
overridesフィールドを使用して推移的依存関係の特定バージョンを強制します
なぜ盲目的なアップグレードがビルドを壊すのか
JavaScriptパッケージ管理の核心的な問題は、古い依存関係を見つけることではありません。それはnpm outdatedが処理します。問題は、「最新」へのアップグレードがピア依存関係の制約、semverの境界、そしてロックファイルが存在する理由という現実を無視することです。
npm updateを実行すると、npmはpackage.jsonのバージョン範囲を尊重します。バージョン3が存在していても、^2.0.0から3.0.0にジャンプすることはありません。これは意図的です。しかし、これは範囲変更を必要とする真の更新が無期限に停滞することも意味します。
ncuは、node_modulesやロックファイルに触れることなく、package.jsonを直接変更(バージョン範囲を更新)することでこれを解決します。インストールのタイミングはあなたが制御します。
Node.js依存関係管理のための最新ncuワークフロー
グローバルインストールはもはやデフォルトのメンタルモデルではありません。ncu v18+では、パッケージマネージャー経由で直接実行します:
npx npm-check-updates
# または
pnpm dlx npm-check-updates
# または
bunx npm-check-updates
これは何も変更せずに更新をチェックします。利用可能なものがsemverレベルごとに色分けされて表示されます:メジャーは赤、マイナーはシアン、パッチは緑です。
重要なフラグは-uで、これがpackage.jsonへの変更を書き込みます。しかし、ここで重要なのは:これはマニフェストのみを更新するということです。ロックファイルは、明示的にnpm installを実行するまで変更されません。
この分離により、より安全な依存関係更新ワークフローが可能になります:
ncu -u --target minorを実行して、非破壊的な変更でpackage.jsonを更新npm installを実行してロックファイルを再生成- テストスイートを実行
- テストが通れば、package.jsonとpackage-lock.jsonを一緒にコミット
メジャー更新については、ncu -u --filter package-nameで個別に処理し、変更履歴を確認してからテストします。
Discover how at OpenReplay.com.
ピア依存関係と互換性チェック
ピア依存関係の競合は、ほとんどのアップグレード失敗の原因です。Reactコンポーネントライブラリは React 18 を必要とするかもしれませんが、プロジェクトは React 17 に固定されています。ライブラリを盲目的にアップグレードするとビルドが壊れます。
ncuの--peerフラグは、更新を提案する前にピア依存関係の互換性をチェックします。これにより、インストールが即座に失敗する可能性のあるアップグレードの提案を防ぎます。
より厳密な制御のために、--targetと組み合わせます:
ncu --peer --target minor
これは、ピア制約を壊さず、メジャーバージョンの境界を越えない更新のみを表示します。
ロックファイルとCIパイプライン統合
ロックファイルは既知の動作状態を表します。それに応じて扱ってください。
CIでは、常にnpm installの代わりにnpm ciを使用してください。ciコマンドは、package.jsonとpackage-lock.jsonが同期していない場合に失敗します。これはまさに望ましい動作です。これにより、誰かがpackage.jsonを更新したがロックファイルの再生成を忘れた状況をキャッチできます。
CIでの自動依存関係更新ワークフローのパターンは次のようになります:
ncu -u --target patch
npm install
npm test
テストが通れば、パイプラインは変更をコミットします。失敗すれば、更新は手動レビューのためにフラグが立てられます。
overridesによる推移的依存関係の制御
時には問題は直接の依存関係ではなく、それらが依存するものにあります。依存関係ツリーの3階層下の脆弱性は、制御していないパッケージの更新を必要とします。
npmのoverridesフィールドを使用すると、推移的依存関係の特定バージョンを強制できます:
{
"overrides": {
"vulnerable-package": "2.0.1"
}
}
これはJavaScriptパッケージ管理の標準的な部分です。上流のメンテナーが依存関係を更新する前にセキュリティパッチが必要な場合に使用します。
結論
依存関係更新の自動化は、すべてを常に更新することを意味しません。発見とインストールを分離し、semverの境界を尊重し、ロックファイルをマニフェストと同期させる反復可能なプロセスを持つことを意味します。
ncuがこのワークフローに適合するのは、package.jsonの更新を別個のステップとして扱うためです。何をアップグレードするか、いつインストールするか、いつテストするかを決定します。ツールは退屈な部分、つまりレジストリのチェックとバージョン範囲の変更を処理し、判断はあなたに委ねます。
パッチは週次で更新します。マイナーは月次でレビューします。メジャーは慎重に処理します。ロックファイルをコミットし続けてください。CIが感謝するでしょう。
よくある質問
npm updateは既存のpackage.jsonバージョン範囲内で新しいバージョンをインストールしますが、メジャーバージョンの境界を越えることはありません。npm-check-updatesはpackage.json自体のバージョン範囲を変更し、メジャーリリースを含む任意のバージョンへの更新を可能にします。ncuはマニフェストを変更し、npm updateはnode_modulesを変更します。
はい。ncuはpackage.jsonのみを変更するため、どのパッケージマネージャーでも動作します。パッケージマネージャーに関係なく、pnpm dlx npm-check-updatesまたはnpx npm-check-updatesで実行してください。ncuがpackage.jsonを更新した後、好みのパッケージマネージャーを使用して更新された依存関係をインストールします。
rejectフラグをパッケージ名またはパターンと共に使用します。例えば、ncu --reject typescriptはTypeScriptを更新から除外します。ncu --reject '/react.*/'を使用して、パターンに一致する複数のパッケージを除外することもできます。これは手動で更新したいパッケージに便利です。
ncu -uの実行はpackage.jsonを変更するだけで、何もインストールしません。リスクは、テストせずにその後npm installを実行することから生じます。更新とインストールの後は、必ずテストスイートを実行してください。最も安全なアプローチとして、ncu -u --target patchを使用してパッチ更新から始めてください。
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.