依存パッケージのバージョン指定に 1.x.x 形式は使わないように
◆ 1.x.x 形式は最低バージョン情報が無い
◆ 依存関係内に同パッケージの古いバージョンで固定されてるのがあると複数バージョンを避けるために古いバージョンになることがある
◆ dedupe するときも必要な最低バージョンより古いのになってしまうことがある
◆ ^ や ~ が覚えられないなら ">=1.2 <2" や "2.3.4 - 3" のような記法も使える
◆ 依存関係内に同パッケージの古いバージョンで固定されてるのがあると複数バージョンを避けるために古いバージョンになることがある
◆ dedupe するときも必要な最低バージョンより古いのになってしまうことがある
◆ ^ や ~ が覚えられないなら ">=1.2 <2" や "2.3.4 - 3" のような記法も使える
semver
依存パッケージ管理があれば どの言語でも似たようなものがありそうですが 一応 Node.js の package.json についてですnpm や yarn でパッケージをインストールすると依存パッケージのバージョンの指定では ~ や ^ が使われます
- ^1.2.3
- ~4.5.6
みたいのです
デフォルトでは ^ になります
これは semver のマイナーアップデートまで許可するもので "^1.2.3" なら 1.2.4 でも 1.4.0 でも指定の範囲に含みます
2.0.0 は含まれません
~ にするとパッチのみを許可して "~4.5.6" なら 4.5.7 は含まれますが 4.6.0 は含まれません
これが覚え辛くよくどっちがどっちかわからなくなります
普段は yarn が勝手に記述するのをそのままで 手動で書き換えることはたまにしかにないのもあって毎回調べています
1.x.x 記法
一応他の書き方もできて 1.x.x や 2.3.x とも書けます依存パッケージの package.json を見てるとたまにこれも見かけます
ぱっと見でバージョンの範囲がわかりやすくこっちのほうが優れてるように見えます
しかし よく考えると問題があるのに気づけると思います
x にしてしまっているので動作確認済みの最低バージョンを正しく指定できません
1.2.3 以上でマイナーアップデートまで許可するときに 1.x.x って書いてしまうと 1.0.0 でもいいってことになってしまいます
実際インストールするときは指定バージョンの範囲で最新版になるし 問題になることはなさそうだし 1.x.x でもいいかなと思ったことはあります
ですが 実際にこの記法を使ってるパッケージが依存関係に紛れていたことで何故か動かなくなった現象が発生しました
1.x.x 形式で動かなくなる場合
パッケージ A がパッケージ B に依存していて "package_b": "1.x.x"
と書いていたとします
パッケージ A が作られたのは パッケージ B が 1.4.5 のときです
パッケージ A はパッケージ B のモジュールの foo 関数を使っています
この関数がパッケージ B に実装されたのは 1.3.0 です
自分のパッケージでは パッケージ A とそれ以外のいくつかのパッケージを依存関係に設定します
その依存関係ツリーのどこかでパッケージ B への依存関係があり そこでは "~1.2.0" が指定されています
"~1.2.0" にマッチするパッケージ B のバージョンは 1.2.9 です
このとき 1.x.x は 1.2.9 でも条件を満たしているので 1.2.9 になるということがあります
その結果 1.3.0 で実装された foo 関数は存在しないので 実行時に関数がみつからないとエラーになります
yarn では経験がないのですが npm の方は古いのに引っ張られて新しいのが入らず苦労したことがあります
dedupe
インストール直後なら動作確認も十分にしてるはずですが dedupe でも発生しますdedupe は依存関係のツリーで重複する部分で保持するパッケージを減らしてくれます
依存関係を減らそうとせず ちょっとしたことでもとりあえず他パッケージをインストールしてるタイプのパッケージが依存関係に含まれると node_modules がかなり重たくなります
数百 MB どころか数 GB になることもわりとあります
少しでも軽くしたいなと dedupe してみると 問題が起きました
上記の例のパッケージ B が "~1.2.0" 用の 1.2.9 と "1.x.x" 用の 1.4.8 の 2 バージョンがあったとき 1.2.9 だけで両方の条件を満たせると判断して 1.4.8 は消されます
そして動いていた部分が動かなくなります
これまで dedupe で動かなくなることを経験していなかったので なぜか急に動かなくなった となって困りました
気づいたのが dedupe 直後でもなく しばらくしてからだったのでさらに原因を見つけるのに苦労しました
こんな書き方もできる
1.x.x のほうがわかりやすいから ^ や ~ より 1.x.x 形式で書くべきだ なんて主張を稀に見ますが 最低バージョン情報がなくなるのでそういうのを真に受けないようにしましょうと言っても ^ や ~ って覚えられないですし毎回調べるのも面倒です
package.json のドキュメントによると semver を参照するらしくて 他にも使える書き方がありました
https://github.com/npm/node-semver#advanced-range-syntax
"package-1": "2.1.5 - 2.9"
だと 2.1.5 かそれより新しいバージョンで 2.10.0 未満のバージョンが対象になります
2.9.1 は対象になりますが 2.10.0 はなりません
もう少し丁寧にこういうふうにも書けます
"package-2": ">=4.5.0 <6.0.0"
4.5.0 以上の 4 系または 5 系バージョンが対象です
これは Python かどこかで見たことのある指定方法ですね
Node.js では見た覚えないですがこれでも通りました
これらなら見てすぐにバージョンの範囲がわかりますし 迷うこともありません
手書きするならこれでいいかもしれませんね