pubspec.yamlのバージョンは空欄でよさそう
はじめに
Flutter では、pubspec.yaml に外部パッケージを定義します。みなさまは、パッケージのバージョンはどのように指定していますか?ほとんどの方は次のように ^[バージョン]
と書いていると思います。
dependencies:
flutter_riverpod: ^2.4.9
^2.4.9
は 2.4.9 以上 3.0.0 未満のバージョンを許可
という意味ですが、特に何も考えずに ^
を使っている人は多いと思います。
他にもいろいろな指定方法があって、次の記事に詳しく書かれていますので是非見てみてください。
上記の pubspec.yaml に対して flutter pub get
を実行すると、2.4.9
がインストールされます。次のように、実際にインストールされたバージョンは pubspec.lock に書かれています。さらに別のパッケージに依存していると、芋づる式に勝手にインストールされて、pubspec.lock に書かれます。
flutter_riverpod:
dependency: "direct main"
description:
name: flutter_riverpod
sha256: da9591d1f8d5881628ccd5c25c40e74fc3eef50ba45e40c3905a06e1712412d5
url: "https://pub.dev"
source: hosted
version: "2.4.9"
・・・
riverpod:
dependency: transitive
description:
name: riverpod
sha256: "942999ee48b899f8a46a860f1e13cee36f2f77609eb54c5b7a669bb20d550b11"
url: "https://pub.dev"
source: hosted
version: "2.4.9"
・・・
state_notifier:
dependency: transitive
description:
name: state_notifier
sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
url: "https://pub.dev"
source: hosted
version: "1.0.0"
パッケージのバージョンアップ
さて、新しいバージョン 2.5.0
がリリースされたらどうしますか?
次のようにバージョンを修正して flutter pub get
を実行すると、2.5.0
がインストールされますよね。
dependencies:
- flutter_riverpod: ^2.4.9
+ flutter_riverpod: ^2.5.0
このように、^[バージョン]
とバージョンを指定して定義し、flutter pub get
を実行してインストールしている人は多いと思います。自分もそうでした。
いちいちバージョンを書き換えるのが面倒
パッケージが増えてくると、いちいちバージョンを書き換えるのが非常に面倒になってきます。例えば firebase 関連のパッケージは 5 個くらいあって(多い場合は 10 個近くも)、かつバージョンアップも頻繁に行われるため、かなりの頻度で pubspec.yaml の修正が必要になってしまいます。
SDK バージョンと合わずにエラーが起きる
パッケージのバージョンを上げたときに、flutter pub get
が次のようなエラーを吐くことがあります。
Running "flutter pub get" in sample...
Resolving dependencies...
The current Dart SDK version is 2.19.6.
Because url_launcher 6.2.2 requires SDK version >=3.1.0 <4.0.0 and no versions of url_launcher match >6.2.2 <7.0.0, url_launcher ^6.2.2 is forbidden.
So, because sample depends on url_launcher ^6.2.2, version solving failed.
この例では、url_launcher 6.2.2 をインストールしようとしたが、現在の Dart SDK 2.19.6 は非対応のためインストールに失敗したことを示しています。
解決するには、
- 現在の Dart SDK を 3.1.0 以上にあげる
- url_launcher のバージョンを 6.1.11 まで下げる
のいずれかの対応が必要です。これを目視で調べながらやるのはとても面倒です。
依存パッケージのバージョンが合わずにエラーが起きる
複数のパッケージが同じパッケージに依存することがあります。その際、それぞれのパッケージが求めるバージョンに齟齬があると flutter pub get
がエラーを吐きます。遭遇したことがある人も多いのではないでしょうか?よく dependency_overrides:
で無理矢理解決しちゃいますよね。
バージョン指定って必要?
そこで、これらの課題を解決する方法が無いか考えてみました。
すると、 バージョンを空欄(もしくは any
)にすれば、インストール可能な最新のバージョンがインストールされる ことがわかりました。つまり、 flutter pub
側でよしなにやってくれるようです。
dependencies:
- flutter_riverpod: ^2.4.9
+ flutter_riverpod:
パッケージがバージョンアップされたら、 pubspec.yaml のバージョンを修正する代わりに、 flutter pub upgrade
を実行するだけで、SDK やパッケージの依存関係を考慮した上で最新のパッケージをインストールしてくれます。
不用意にバージョンアップされたくない
不用意にバージョンアップされたくない場合は ^
を無くしてバージョンを固定すれば OK です。
dependencies:
- flutter_riverpod: ^2.4.9
+ flutter_riverpod: 2.4.9
実例
私の個人開発の実例を紹介します。
私の個人開発のプロジェクトでは、flutter pub upgrade
による意図しない不具合を防ぐために、firebase 関連、 ナビゲーションの auto_route (go_router)、riverpod はバージョンを固定して、他はすべて空欄にしています。
マイナーリリース時は flutter pub upgrade
を実行してまとめてバージョンアップし、大きめのリリース時は固定にしているバージョンを書き換えてアップデートしています。
dependencies:
auto_route: 7.8.4
badges:
cached_network_image:
cloud_firestore:
collection:
cupertino_icons:
device_info_plus:
device_preview:
device_preview_screenshot:
firebase_analytics:
firebase_app_check:
firebase_auth:
firebase_core: 2.22.0
firebase_crashlytics:
firebase_storage:
fl_chart:
flutter:
sdk: flutter
flutter_cache_manager:
flutter_localizations:
sdk: flutter
flutter_native_splash:
flutter_riverpod: 2.4.5
freezed_annotation:
gap:
intl:
introduction_screen:
json_annotation:
json_serializable:
material_color_utilities:
package_info_plus:
quiver:
recase:
riverpod_annotation:
roggle:
shared_preferences:
sleek_circular_slider:
speech_balloon:
star_menu:
url_launcher:
visibility_detector:
dev_dependencies:
auto_route_generator:
build_runner:
flutter_gen_runner:
flutter_launcher_icons:
flutter_test:
sdk: flutter
freezed:
pedantic_mono:
riverpod_generator:
riverpod_lint:
firebase 関連は firebase_core しかバージョンを指定していません。これだけで、その他の firebase 関連のパッケージも、良い感じにバージョンをそろえることが出来ます。riverpod や auto_route 関連も同様です。
まとめ
これまで、pubspec.yaml に書くパッケージのバージョン指定を ^[バージョン]
と書き、バージョンアップの度に pubspec.yaml を修正していました。
すると、Flutter SDK をバージョンアップしたり、パッケージのバージョンアップの度にエラーが起き、また管理も煩雑になっていました。
本記事では、これらの問題を解決するために、次の 3 点のことについて紹介しました。
- pubcpec.yaml のバージョン指定は空欄にする。
- パッケージをバージョンアップしたい場合は
flutter pub upgrade
を実行する。 - 固定にしたければ
^
を外してバージョン指定する(例2.5.0
)。
pubspec.yaml まわりのエラーで苦しまれている人や、管理が大変だと感じている人の参考になれば幸いです!
最後に
Flutter 大学という Flutter エンジニアに特化した学習コミュニティに所属しています。オンラインでわいわい議論したり、Flutter の最新情報をゲットしたりできます!ぜひ Flutter 界隈を盛り上げていきましょう!
Discussion
バージョンを空白にすると管理は楽になるのですが、その分ライブラリの破壊的な変更を意図せず取り入れることになるため、注意が必要ではないかなと感じました。
こちらのdocの記載があるのですが、
^2.0.0
という表記は>=2.0.0 <3.0.0
を示します。このため、^2.0.0
と指定しflutter pub upgrade
をしている限りは、v2系の最新の(かつ、他のライブラリと整合性の取れた)バージョンが取得されます。[1]dartのライブラリはsemantic versioningに従うことが推奨されています。このため、メジャーバージョンが上がるケースでは、破壊的な変更が含まれている可能性があります。
https://semver.org/lang/ja/#spec-item-8 [2]
^2.0.0
と記載すると、3.0.0
がリリースされたとき、flutter pub get
やflutter pub outdated
コマンドで「新しいライブラリが出ていること」が通知されます。この通知をもとにpub.devやGitHubのchangelogを確認し、ライブラリの更新をするフローが、手間ではあるのですが安全側に倒れているように思います。doc内ではGiven version or laterが推奨されているようです ↩︎
厳密にはバージョンがずれるのですが、日本語訳があるので2.0.0を参照してます ↩︎
コメントありがとうございます!おっしゃるとおりだと思ったので追記させていただきました。ありがとうございます!
追記ありがとうございます!
Flutter大学さんの記事は参考にされる方が多いので、メリットとデメリットが併記されていると、初心者の方でも判断しやすいのかなと。安心しました。
自分も色々試したのですが、^を削除してflutter pub upgrade --major-versionsを実行すると、^を削除したパッケージのみバージョンを最新にして、新しいバージョンの記載(例:firebase_core: ^3.1.11)にも変更してくれます。
pubspec.yamlに対象のバージョン縛りもつくし、lockのバージョンがそれ以上になることもないので、ひとまずはこの方法が良いかなと思っています。
^を削除しなかったパッケージはそのままのバージョンを保持してくれます。
また新しいバージョンがなかった場合は^が付加されません。
全部のパッケージを更新したい場合は^を置換検索で一気に削除して実行します。
また、新しいバージョンがなかったものは^付きにならないので、そのままでロックしたい場合は^を付加すると、次の時にflutter pub upgrade --major-versionsを実行した時に勝手にバージョンが上げられてしまうのを避けられます。