意味のあるバージョン付け npm install に依存する番号システム
Semverの3つの数字は契約です。MAJORは破壊、MINORは追加、PATCHは修正——そしてnpm install後にビルドが破壊された場合、9割はその契約を無視しているのです。ここでは、数値システムの仕組み、package.jsonにおける^と~が実際にどう機能するか、そしてロックファイルをコミットする必要性について説明します。
ビルドが壊れた。金曜日までは問題なかった。 npm install 月曜日に取り込まれた react-query@5 そして、あなたのハックの半分が消えてしまった。以前はなかったスタックトレースが現れ、どこかでは変更ログが塵に変わっている。
これは意味のあるバージョン付けの物語だ。特に、それはあなたの責任だ。
3つの数字が実際に意味すること
MAJOR.MINOR.PATCH — それだけだ。3つのスロット、3つのルール:
- PATCH (1.2.3 → 1.2.4):バグ修正。あなたのコードに変更は必要ない。ただ、壊れにくい動作が増えるだけ。
- MINOR (1.2.3 → 1.3.0):新しい機能が追加され、バックワード互換性がある。使う必要はないが、そこに存在する。
- MAJOR (1.2.3 → 2.0.0):何かが壊れた。関数がリネームされ、削除され、または署名が変わった。古いAPIは消えたり、動作が異なる。
すべての3つのキーワードは バックワード互換性。MINORとPATCHは約束:「すでに使っているものを壊していない」というものだ。MAJORは警告:「壊した」ということだ。
メンテナーがMAJORを上げたとき、あなたが気づかなかったのは、package.jsonにピンを置き、ロックファイルが古かったからだ ^1.0.0 スペックはまったく設計通りに動作していた。
意味のあるバージョン付けの社会的契約
意味のあるバージョン付けは規則であり、法則ではない。パッケージはそれを守っていながら、MINORバージョンで破壊的な変更をリリースすることがある。その場合、メンテナーは不誠実である。しかし、パッケージが適切にMAJORを上げて破壊を示し、あなたが無視して取り込んだ場合、あなたが自らのビルドを壊したのだ。
これが変更ログが存在する理由だ。A CHANGELOG.md 「deprecatedを削除し、 v1Api に置き換える」という項目は、メンテナーが契約を果たしていることを示している。それを読まなければ、それはあなたが自分の責任を無視しているということだ。変更ログは2分で読める。それを読まなければ、発生するデバッグセッションはそれほどではない。 v2Api 「instead」は、メンテナーが自らの責任を果たしていること。読まないのは、あなたが自分の責任を無視していること。変更ログは2分で読める。それによって防がれるデバッグセッションは、それではない。
^ と ~ — 実際のメカニズム
in package.json, ^ (キャタップ) と ~ (ティルド) はバージョン範囲を定義する。見た目は似ているが、動作はまったく異なる。
キャタップ (^): MAJORを上げないすべてのバージョンを許可する。これはnpmが npm install some-package.
^1.2.3を実行するときにデフォルトとして使う。>=1.2.3 <2.0.0^0.2.3を実行するときにデフォルトとして使う。>=0.2.3 <0.3.0に解決される。0.x特別なケース:^0.0.3を実行するときにデフォルトとして使う。>=0.0.3 <0.0.4—0.0.xMINORを破壊的と見なす
正確にピン止めし、わずかな余地はない ティルド (~):
~1.2.3を実行するときにデフォルトとして使う。>=1.2.3 <1.3.0~1.2を実行するときにデフォルトとして使う。>=1.2.0 <1.3.0PATCH更新のみを許可し、指定されたMINOR範囲内で。~1.2.0~1を実行するときにデフォルトとして使う。>=1.0.0 <2.0.0— 同じである^1.0.0— これに等しい
この時点では
| 範囲 | それは許容するもの | 具体的な一致 |
|---|---|---|
1.2.3 | ちょうどこのバージョン | のみ 1.2.3 |
^1.2.3 | MINOR/PATCH ≥ 1.2.3 すべて | 1.2.4, 1.3.0, 1.99.0 — NOT 2.0.0 |
^0.2.3 | 0.2.x 内のPATCHのみ | 0.2.4, 0.2.99 — NOT 0.3.0 |
~1.2.3 | 1.2.x 内のPATCHのみ | 1.2.4, 1.2.99 — NOT 1.3.0 |
~1.2 | 1.2.x のすべてのPATCH | 1.2.0, 1.2.1, 1.2.99 |
>=1.2.3 <2.0.0 | 明示的な範囲 | ^1.2.3 と同じ結果 |
1.2.x | 1.2 のすべてのPATCH | 1.2.0, 1.2.1, 1.2.99 |
* | すべてのもの | npmが今日インストールするもの |
の * 範囲は「信頼していいよ」というバージョン戦略だ。あなたはピンを置いていない。もしライブラリが完全にリワードされたAPIを提供したら、次回の v9.0.0 でそれを取得するだろう。 npm install キャッシュがクリーンであれば。トップレベルのアプリケーションでしか使わない場合に限って、そしてそれすらも、再現性が本当に問題にならない場合に限って(それは問題だ)。
プレリリース識別子
安定リリースの前に、メンテナーはプレリリースラベルを付ける:
1.0.0-alpha.1— 早期、不安定、APIはおそらくまだ変更中1.0.0-beta.2— 完全な機能、まだテスト中、いくつかの不具合を期待する1.0.0-rc.1— リリース候補、最終テストで何かが見つからない限りは、生産環境で使用できる
プレリリースは 安定リリースより 低い: 1.0.0-alpha.1 < 1.0.0そして特に、 ^1.0.0 は ない インストールされる。 2.0.0-beta.1 — プレリリースは、明示的に範囲に指定しなければマッチしない。これは、あなたが誤ってアルファをオプトインしたことを防ぐ行動だ。
パッケージを消費している場合、プレリリースしか持たない場合、フルバージョン文字列をピン止めする: "some-package": "1.0.0-beta.2"。プレリリースを使用する場合、メンテナーがそれを慎重に扱っていることを知っている必要がある — 多くはそうではない。 ^ または ~ プレリリースを含む場合、メンテナーがそれらを慎重に扱っていることを知っている限り。
範囲をコミットする前に確認する
範囲を package.jsonにピン止めする前に、実際にインストールするものについて確認することが価値がある。 意味のあるバージョン計算機 バージョン範囲と候補バージョンのリストを取って、どのバージョンがマッチするかを表示する。特定のバージョンが範囲をカバーしているか、またはPRの範囲がおかしい場合に役立つ。 ~2.3 必要な特定のバージョンをカバーしている場合、またはPRをレビューしているときに範囲がずれている場合。
3つの失敗モード
意味のあるバージョン関連のビルド失敗は、次の3つのパターンのいずれかに従う。
^+ MAJORアップ + ロックファイルが削除された: あなたは^1.0.0をピン止めし、メンテナーが2.0.0をリリースし、ロックファイルが削除されたり、コミットされなかった。CIが2.0.0をインストールした。解決策:すべてのプロジェクトにロックファイルをコミットする。例外はない。*ライブラリで使用した あなたはライブラリの作者で、依存関係に*を使用した。あなたのパッケージのすべての下流ユーザーが、あなたのワイルドカードを継承する。あなたはその依存関係グラフの問題を自ら作り出した。解決策:npmに配布するすべてのものに明示的な範囲を使用する。- ロックファイルなしのプレリリース: 緩やかな範囲が
1.0.0-alpha.3を引き込み、APIがalpha.1から変更された。何も機能しない。解決策:プレリリースを明示的にピン止めし、そして、言うまでもないが、ロックファイルをコミットする。
変更ログを読む
あなたの依存関係ツリーのどこかでMAJORバージョンがリリースされた場合、2分間変更ログを読む。メンテナーがそれを書いたのは、あなたが3時頃のスタックトレースから破壊を逆算する必要がないようにするためだ。
ライブラリがMINORバージョンで破壊的な変更をリリースし、変更ログがない場合、それは不誠実である。問題をファイルし、公開して指摘する。しかし、MAJORが明確にあった場合、移行ガイドが詳細で、あなたが見ずに取り込んだ場合、ツールがまさにあなたが指示した通りに動作した。契約は3つの数字で書かれていた。あなたがただそれを読まなかっただけだ。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
