🦆

pubspec.yamlのバージョンは空欄でよさそう

2023/12/16に公開
4

Created by ChatGPT

はじめに

Flutter では、pubspec.yaml に外部パッケージを定義します。みなさまは、パッケージのバージョンはどのように指定していますか?ほとんどの方は次のように ^[バージョン] と書いていると思います。

pubspec.yaml
dependencies:
  flutter_riverpod: ^2.4.9

^2.4.92.4.9 以上 3.0.0 未満のバージョンを許可 という意味ですが、特に何も考えずに ^ を使っている人は多いと思います。

他にもいろいろな指定方法があって、次の記事に詳しく書かれていますので是非見てみてください。

https://qiita.com/kurun_pan/items/76e13bfd03fd3dec1e27#バージョンの指定方法

上記の pubspec.yaml に対して flutter pub get を実行すると、2.4.9 がインストールされます。次のように、実際にインストールされたバージョンは pubspec.lock に書かれています。さらに別のパッケージに依存していると、芋づる式に勝手にインストールされて、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 がインストールされますよね。

pubspec.yaml
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 側でよしなにやってくれるようです。

pubspec.yaml
dependencies:
-  flutter_riverpod: ^2.4.9
+  flutter_riverpod:

パッケージがバージョンアップされたら、 pubspec.yaml のバージョンを修正する代わりに、 flutter pub upgrade を実行するだけで、SDK やパッケージの依存関係を考慮した上で最新のパッケージをインストールしてくれます。

不用意にバージョンアップされたくない

不用意にバージョンアップされたくない場合は ^ を無くしてバージョンを固定すれば OK です。

pubspec.yaml
dependencies:
-  flutter_riverpod: ^2.4.9
+  flutter_riverpod: 2.4.9

実例

私の個人開発の実例を紹介します。

私の個人開発のプロジェクトでは、flutter pub upgrade による意図しない不具合を防ぐために、firebase 関連、 ナビゲーションの auto_route (go_router)、riverpod はバージョンを固定して、他はすべて空欄にしています。

マイナーリリース時は flutter pub upgrade を実行してまとめてバージョンアップし、大きめのリリース時は固定にしているバージョンを書き換えてアップデートしています。

pubspec.yaml
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 界隈を盛り上げていきましょう!

https://flutteruniv.com?invite_id=9hsdZHg0qtaMIr6RPRulAaRJfA83

Flutter大学

Discussion

koji-1009koji-1009

バージョンを空白にすると管理は楽になるのですが、その分ライブラリの破壊的な変更を意図せず取り入れることになるため、注意が必要ではないかなと感じました。

https://dart.dev/tools/pub/dependencies

こちらの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]

メジャーバージョン X (X.y.z | X > 0)は、パブリックAPIに対して後方互換性を持たない変更が取り込まれた場合、上げなければなりません(MUST)。その際にマイナーおよびパッチレベルの変更も含めてもよいです(MAY)。メジャーバージョンを上げた際には、パッチおよびマイナーバージョンを0にリセットしなければなりません(MUST)。

^2.0.0と記載すると、3.0.0がリリースされたとき、flutter pub getflutter pub outdatedコマンドで「新しいライブラリが出ていること」が通知されます。この通知をもとにpub.devやGitHubのchangelogを確認し、ライブラリの更新をするフローが、手間ではあるのですが安全側に倒れているように思います。

脚注
  1. doc内ではGiven version or laterが推奨されているようです ↩︎

  2. 厳密にはバージョンがずれるのですが、日本語訳があるので2.0.0を参照してます ↩︎

すさすさ

コメントありがとうございます!おっしゃるとおりだと思ったので追記させていただきました。ありがとうございます!

koji-1009koji-1009

追記ありがとうございます!
Flutter大学さんの記事は参考にされる方が多いので、メリットとデメリットが併記されていると、初心者の方でも判断しやすいのかなと。安心しました。

TASKTASK

自分も色々試したのですが、^を削除してflutter pub upgrade --major-versionsを実行すると、^を削除したパッケージのみバージョンを最新にして、新しいバージョンの記載(例:firebase_core: ^3.1.11)にも変更してくれます。
pubspec.yamlに対象のバージョン縛りもつくし、lockのバージョンがそれ以上になることもないので、ひとまずはこの方法が良いかなと思っています。
^を削除しなかったパッケージはそのままのバージョンを保持してくれます。
また新しいバージョンがなかった場合は^が付加されません。
全部のパッケージを更新したい場合は^を置換検索で一気に削除して実行します。
また、新しいバージョンがなかったものは^付きにならないので、そのままでロックしたい場合は^を付加すると、次の時にflutter pub upgrade --major-versionsを実行した時に勝手にバージョンが上げられてしまうのを避けられます。