この記事はFlutter Advent Calendar 2022の24日目の記事になります。クリスマスには技術記事で歯向かっていこう。
2024/1/7 melos 3.4.0向けに記事とソースコードを一部アップデートしました。
前置き
以前に Flutterのマルチパッケージの記事を投稿しました。
そもそもFlutterではマルチパッケージ構成を採用することはあまり多くないかもしれません。しかし、大規模なアプリを作る場合にRipositoryを分割してコード管理する場合や、複数のFlutterアプリを同じRipositoryで管理したい、みたいなケースにおいて、マルチパッケージ構成を選択することもあるかと思います。
今回はより実用的なマルチパッケージプロジェクトの構築を目指し、マルチパッケージ構築をサポートする「melos」を試していきます。
melosはいわゆるMonorepoと呼ばれるような、複数パッケージを持つDartプロジェクトを管理するためのツールです。flutterfireなどの有名ライブラリのプロジェクトにも導入されています。Invertase社が開発しています。
melosは以下のような機能を持ちます。
- バージョン管理と変更ログの自動生成
- pub.dev へのパッケージの自動公開
- ローカル パッケージのリンクとインストール
- 複数のパッケージで同時にコマンドを実行する
- ローカル パッケージとその依存関係のリスト
どちらかというとライブラリ開発において力を発揮する印象を受けますが、普通のFlutterアプリ開発においても使える機能があります!
Sample
app_1
とapp_2
の2つのFlutterアプリを作成し、UIを提供するapp_common
パッケージを参照する構築です。
構築手順
melos公式のGetting Startedを参考に構築します。
- Flutterをインストール
melosをインストール
dart pub global activate melos
(3.x系より) プロジェクトのルートに
pubspec.yaml
を設定ベースの設定を作成します。以下はサンプルです。
name: melos_test_workspace environment: sdk: ">=3.0.0 <4.0.0"
上記を設定後、
dart pub add melos --dev
を実行してインストール済のmelosをdev_dependenciesとして追加します。詳しい説明は以下の通り
https://melos.invertase.dev/getting-startedプロジェクトのルートに
melos.yaml
を作成以下はサンプルです。 必須項目はname(プロジェクト名)とpackages(melosで管理するパッケージ群)になります。packagesは任意の複数のフォルダを指定できます。
name: your_project_name packages: - packages/**
それ以外にも、SDKの場所の指定(fvmなどを導入している場合などに)やIDE、Gitに関する設定も可能です。各自で必要なものをセッティングしましょう。 Configuration overview
設定したパッケージの管理場所にパッケージを作成、移動
.gitignore
をルートや各パッケージに設定
機能例
melos bootstrap
による初期設定
melos bootstrap
は全てのプロジェクトでpub getを実行してくれます。
また、bootstrapを実行するとIDEの設定も作成してくれます。下記はAndroid Studioの例で、IntelliJ系のRun Configが作成されます。
これ以外にも、後述するスクリプトのフックと合わせて初期設定をまとめることも可能です。
※パッケージ公開周りにおける利点もありますが、今回は省略します。
melos list
による依存関係の可視化
プロジェクト内のパッケージの依存関係を可視化することができます。
特にmelos list --graph
によるJSON形式での可視化が便利です。
% melos list --graph { "app_1": [ "app_common" ], "app_2": [ "app_common" ], "app_common": [] }
スクリプトを設定して実行する
おそらくmelosを使う上で一番よく使う機能になります。
スクリプトを組めるため、これによって各パッケージの操作を用意にできます。
各パッケージで任意のコマンドを実行する
melos exec
コマンドで、各パッケージで任意のコマンドを実行できます。
例えば、freezedなどを使用している場合で、build_runner
によるファイルの自動生成を行う場合に、一気に実行できるようにします。
dependsOn
フィルターを使用してbuild_runner
を含むパッケージに対して実行できるようにします。
scripts: build_runner: exec: flutter pub run build_runner build --delete-conflicting-outputs packageFilters: dependsOn: 'build_runner' description: "run build_runner in projects including build_runner"
3.0より前のスクリプトはここをクリック
scripts: build_runner: exec: flutter pub run build_runner build --delete-conflicting-outputs select-package: depends-on: "build_runner" description: "run build_runner in projects including build_runner"
melosのlifecycle系コマンドをフックする
bootstrap
、clean
、version
の各コマンドの実行前後に好きなスクリプトを差し込めます。
前に実行したいならpreコマンドを、後に実行したいならpostコマンドを追加します。
例えば、bootstrap
の後に前述のbuild_runnerの実行を行うスクリプトは以下のように書けます。
command: bootstrap: hooks: post: melos run build_runner
3.0より前のスクリプトはここをクリック
scripts: postbootstrap: melos run build_runner
任意のスクリプト実行
melos run
コマンドで、scriptsで定義したスクリプトを動かすことができます。
また、run
コマンドは任意のスクリプトを実行できます。
fastlaneなどを用いたCI/CD構築ほか、いろいろ活用できます。
scripts: fastlane_script: run: | cd packages/app_1 fastlane hoge
おわりに
今回は簡単な例で紹介しましたが、スクリプトを組み合わせることで多彩な管理手法を構築できます。
Flutterで大規模なアプリを構築する際は一考の余地があるかと思います。
今回の記事やサンプルでもし間違っている点があればぜひお知らせください🙏