【Flutter】Melosで機能毎にパッケージを分割する
サンプル
今回作成したサンプルアプリはこちらになります。
はじめに
Flutter、もといDartにはMelosという、複数パッケージを管理するためのツールが存在しています。これを使用してFlutterプロジェクトのアーキテクチャをいい感じに分割できそうでは?と思ったので色々調べて試してみました。
やりたいこと
私はFlutterの開発でNow in AndroidやDroidKaigi2023 Appのように機能やレイヤ毎にディレクトリを分割していました。
しかし、DartにはKotlinでいうinternal
修飾子のようなパッケージプライベートを提供する機能は存在しないため、常にどこに依存しているか、きちんと機能単位で独立しているかを意識しながらコーディングする必要がありました。
そこで、機能毎にパッケージとして分割することでその煩わしさから抜け出してみようと思います。
Melosとは
公式サイトによると、
Melos is a CLI tool used to help manage Dart projects with multiple packages (also known as mono-repos).
Splitting up large code bases into separate independently versioned packages is extremely useful for code sharing. However, making changes across many repositories is messy and difficult to track, and testing across repositories gets complicated. Melos helps solve these issues by allowing multiple packages to work together within one repository, whilst being totally independent of each other. Features include:
- Automatic versioning & changelog generation.
- Automated publishing of packages to pub.dev.
- Local package linking and installation.
- Executing simultaneous commands across packages.
- Listing of local packages & their dependencies.
ということで、モノレポ構成のプロジェクト管理を補助してくれるツールになります。
Melosの機能の内、
- ローカルパッケージのリンクとインストール
- パッケージ間での同時コマンド実行
- ローカルパッケージとその依存関係の一覧表示
を活用することで、Flutterプロジェクトのパッケージ分割がうまくできそうです。
Melosを使ってアプリを作ってみる
サンプルとしてカウントアップ/ダウンするだけのアプリを作成しました。
Melosを使う構成の参考にしてもらえればと思います。
使用環境は以下になります。
fvm: 2.4.1
melos: 4.0.0
プロジェクト作成
まずは以下のコマンドでMelosを有効化します。
dart pub global activate melos
続いてプロジェクトを作成します。
Melosを使用する場合はプロジェクトルートになるので、ルートにmelos.yaml
を追加しつつ、必要な設定を公式ドキュメントを参考に記述します。
今回はfvmを使用しますので、sdkPath
の記述を追加しています。
パッケージ作成
続いて必要なパッケージを作成します。
今回は以下の単位でパッケージを分割し、ルールに沿って保存先を決定します。
- アプリ
アプリに関する機能(ルーティング等) - UI
UIを構成するWidgetやテーマ - モデル
プロジェクトで使用するデータクラス - カウント
カウントアップを実現するためのロジック - メインページ
アプリのメインとなるページ - テスト
テスト時に使用する便利処理
melos list --graph
でJSON形式でパッケージ間の依存関係を出力することができます。
{
"count": [
"model",
"testing"
],
"main": [
"count",
"model",
"ui",
"testing"
],
"melos_sample_app": [
"main",
"model",
"ui",
"count"
],
"model": [],
"testing": [],
"ui": [
"model"
]
}
画像で欲しい場合はmelos list --gviz
とすることでDOT言語で出力することができるので変換することで表示できます。こちらの方がぱっと見で依存関係が把握できてよさそうです。(DOT言語初めて知った…🤔)
スクリプトの作成
続いてmelosのスクリプトを作成します。
複数のパッケージが存在する場合、通常はパッケージごとにflutter pub get
やflutter build runner build run -d
等のコマンドを実行する必要があり、非常に面倒です。これを解決してくれるのがスクリプトで、melos.yaml
にコマンドを定義して、melos run ~~
とすることで全パッケージに向けてコマンドを実行することができるようになります。(公式ドキュメント)
ついでにGutHub Actionsでリントとテストのワークフローを設定しておくと良いです。
ワークフロー内でもmelosに定義したスクリプトを使用することができます。今回はlint
とtest
を実行することでコードの品質を担保するワークフローを作成しています。
実装する
ここまででプロジェクトの環境整備はできましたので、あとはひたすら実装するのみです。新しくファイルを作成する際にはどのパッケージにいるべきかを考えて、適切な場所に置くように心がけましょう。
まとめ
Melosを使うことで、比較的容易にマルチパッケージ構成のアプリを作ることができました。
小規模なアプリではそこまで恩恵はなさそうですが、規模が大きくなってもコードを綺麗に保ちやすくなるかと思います。
今回の構成だと、外部のライブラリへの依存が各パッケージに分散してしまっており、バージョン管理が面倒になりそうです。この辺を解決できる方法があればまた記事にできればと思います。
Discussion