alpha Lounge

20%の技術記事とオタクネタ

【Flutter】(3.4.0対応) melosでマルチパッケージプロジェクトを管理する / Flutter multi package app sample with melos

この記事はFlutter Advent Calendar 2022の24日目の記事になります。クリスマスには技術記事で歯向かっていこう。

2024/1/7 melos 3.4.0向けに記事とソースコードを一部アップデートしました。

前置き

以前に Flutterのマルチパッケージの記事を投稿しました。
そもそもFlutterではマルチパッケージ構成を採用することはあまり多くないかもしれません。しかし、大規模なアプリを作る場合にRipositoryを分割してコード管理する場合や、複数のFlutterアプリを同じRipositoryで管理したい、みたいなケースにおいて、マルチパッケージ構成を選択することもあるかと思います。

今回はより実用的なマルチパッケージプロジェクトの構築を目指し、マルチパッケージ構築をサポートする「melos」を試していきます。

melos.invertase.dev

melosはいわゆるMonorepoと呼ばれるような、複数パッケージを持つDartプロジェクトを管理するためのツールです。flutterfireなどの有名ライブラリのプロジェクトにも導入されています。Invertase社が開発しています。

melosは以下のような機能を持ちます。

  • バージョン管理と変更ログの自動生成
  • pub.dev へのパッケージの自動公開
  • ローカル パッケージのリンクとインストール
  • 複数のパッケージで同時にコマンドを実行する
  • ローカル パッケージとその依存関係のリスト

どちらかというとライブラリ開発において力を発揮する印象を受けますが、普通のFlutterアプリ開発においても使える機能があります!

Sample

github.com

app_1app_2の2つのFlutterアプリを作成し、UIを提供するapp_commonパッケージを参照する構築です。

構築手順

melos公式のGetting Startedを参考に構築します。

  1. Flutterをインストール
  2. melosをインストール

     dart pub global activate melos
    
  3. (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

  4. プロジェクトのルートにmelos.yamlを作成

    以下はサンプルです。 必須項目はname(プロジェクト名)とpackages(melosで管理するパッケージ群)になります。packagesは任意の複数のフォルダを指定できます。

    name: your_project_name
    packages:
      - packages/**
    

    それ以外にも、SDKの場所の指定(fvmなどを導入している場合などに)やIDE、Gitに関する設定も可能です。各自で必要なものをセッティングしましょう。 Configuration overview

  5. 設定したパッケージの管理場所にパッケージを作成、移動

  6. .gitignoreをルートや各パッケージに設定

機能例

melos bootstrapによる初期設定

Bootstrap Command

melos bootstrapは全てのプロジェクトでpub getを実行してくれます。
また、bootstrapを実行するとIDEの設定も作成してくれます。下記はAndroid Studioの例で、IntelliJ系のRun Configが作成されます。

melosのIntelliJサポート

これ以外にも、後述するスクリプトのフックと合わせて初期設定をまとめることも可能です。

※パッケージ公開周りにおける利点もありますが、今回は省略します。

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系コマンドをフックする

Hooks

bootstrapcleanversionの各コマンドの実行前後に好きなスクリプトを差し込めます。 前に実行したいなら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で大規模なアプリを構築する際は一考の余地があるかと思います。

今回の記事やサンプルでもし間違っている点があればぜひお知らせください🙏