JavaScript
Node
npm

npmのモジュールバージョン指定におけるチルダ(~)とキャレット(^)の違いについての直感的な理解

More than 1 year has passed since last update.

package.jsonのdependencies/devDependenciesにおいて、左端が0ではない、z.y.zという3桁のバージョンを指定する場合、以下のとおり。

記法 種別 意味 問題点など
^x.y.z キャレット表記 セマンティックバージョニングに従う。つまり、メジャーバージョンxを指定し、マイナーバージョンyの上昇、パッチバージョンzの上昇は互換性があるはずだと信じて、「x.{y以上}.{yが同じならz以上、yが上昇していれば任意} 」にあてはまる最新のものを使う。 開発時点と、ソース共有を経ての再ビルド(npm install)時の間で、NPMリポジトリ上の対象パッケージのバージョンが上がっている場合、より新しいものが使われることになる可能性があるが、セマンティックバージョニングの仕様に厳密に従わないパッケージは世の中に結構あるのではまり易い。
~x.y.z チルダ表記 セマンティックバージョニングにおける「マイナーバージョンが上がっても互換性が保たれるはずだ」という建前を信じないが、パッチバージョン上昇だったら互換性があるだろうとは信じて、「x.y.{z以上}」にあてはまるものを使う。 キャレット表記に比べて、上記の可能性がパッチバージョンのみなので少ない。とはいえ、はまるときははまるだろう。
x.y.z 固定 指定したバージョン「x.y.z」に厳密にあてはまるものを使う。 開発時と異なるバージョンが使用される問題は回避できるが、たとえばセキュリテイ問題があってそのバージョンのNPMがリポジトリから削除された場合に(互換性のある後継バージョンがあるのに)ビルド不可能になったり、許容できるバージョン上昇を指定できないなど、セマンティックバージョンのメリットを全く享受できない。

いずれも問題があるので、^なり~で指定した上で、package-lock.jsonなりyarn.lockを併用するのが正しい(それぞれNPM5、yarnのデフォルト動作)。

これらのロックファイルを使うのは、セマンティックバージョニングの建前と本音を使いわけることである。つまり、^~をつかって「このバージョンの範囲なら、互換性に問題ないはずだ」という希望と理想をpackage.jsonに記す。それはその上で、「実際にはこのバージョン使ってビルドしましたよ、動作保証するのはこっちなんで、こちらをお使い下さいね、げっひっひ」とlockファイルを裏で提供する。

左端の桁が0であったり、3桁以外の場合を含めてはこちらの記事などを参照のこと。