Managing multi-package Flutter projects with Melos
Most of the time when you create a Flutter project. You work with a single package. The project consists of a single
lib folder. You put all your features and utilities in the same package. But there are projects which break their features and utilities into multiple packages. This helps in better separation of concerns and allows the team to open-source some of their packages. Here is a diagram of how a multi-package project will look like:
Here we have divided the project into three layers. The first layer is the root project which will hold common configurations that applies to all the different packages in the project. The 2nd layer is having independent feature packages that do not depend on each other. The 3rd layer consists of utility packages that are used in multiple feature packages. I won’t dive deep into how to create or structure a multi-package flutter project. This article will focus on solving a particular challenge that is typically faced in a multi-package flutter project.
In a single package flutter project running the following tasks is dead simple:
flutter pub get
- Generating code coverage i.e
flutter test --coverage
But running the same tasks in a multi-package flutter project can be challenging because you need to run those tasks in every package inside your project and give a summarised result at the end of completion of the task. Now we know what the challenge is. Let’s discuss what are the possible solutions for it.
There are 2 possible solutions to solve this challenge. Let’s look at the first one:
- Writing bash scripts for various tasks.
This is definitely a solution but not a smart solution. You need to first write a script that will find out all the packages in your project and run one of the above tasks in it. You also need to make sure that you display output in a pretty format to make things readable. If you are more of a GUI guy then you need to create some sort of configuration in your IDE to run your scripts through GUI.
- Integrating Melos into your project.
This is a smart solution over the first one which I highly recommend. So let’s discuss in details what Melos is and how to integrate it into your multi-package project.
Melos is a CLI tool for managing Flutter/Dart project with multiple packages.
- Automatic versioning & changelog generation.
- Automated publishing of packages to
- Local package linking and installation.
- Executing simultaneous commands across packages.
- Listing of local packages & their dependencies.
Now let’s see how we can perform all the above tasks using Melos.
Note: Please download the starter project if you wanna learn by doing. There is another branch where you can find the final version of the project.
Let’s install Melos first. I assume you have already installed Flutter SDK and set the Flutter and Dart path to
bash_profile . Run the following command in your terminal:
The next step is to open up your starter project in your IDE. I prefer using Intellij and would show you some awesome GUI features provided by Melos. The project structure should look like the following:
Now create a file named
melos.yamlin your root app. and copy the following content to it:
Let’s understand the above script:
name : You have to give the name of your project. You can find it inside the
pubspec.yaml of the root project.
packages : This list should contain paths to the individual packages within your project. Each path can be defined using the glob pattern expansion format.
Now run the following command in your terminal from your root project to link all your local packages together and update the dependencies i.e
flutter pub get .
You should see the following output after running the above command:
You can read why you need to bootstrap Melos here. To be precise it’s one of the important commands you should execute when setting up Melos in a project or you performed a cleanup in your project.
You can execute this command when you want to remove temporary files from your project(build artifacts, pub files etc). This is how the command looks like:
Now you will work on creating different commands to achieve the tasks which we mentioned at the starting of the article.
a. Running test cases in specific packages
Write the following command in your
Let’s understand what’s happening in the above script:
1) You have created a custom script i.e
test:selective_unit_test that once executed will show you an option to select a package whose unit tests you wanna run.
2) Melos provide powerful filtering options to select packages that meet the filter criteria. In the above script, you used
--dir-exists="test" as the filtering option. This will filter all the packages which consist of
testfolder. You can find more filtering options on their website.
--fail-fast will immediately terminate the script execution if it encounters a failing test case.
4) You can give a human-readable description to each script by using the
5) You must be wondering why did you name this command like
test:selective_unit_test . The next command will answer your question. 😃
6) You can read in detail what
melos exec does. Basically, it will execute the command or script in every package inside your project.
Now run the following command:
You will be seeing the following output:
The above command was able to find out these packages which contained the folder test. Enter 2 as the option and you will see the following output:
b. Running test cases in all the packages
Now write the following command which will run all the unit test cases in the project. This won’t prompt any option selection:
Let’s discuss what the above command does:
- This command will basically run the previous command with
--no-selectas an argument. That means, run all the unit tests.
- You can use
melos run testto run this command. You named this command
testbecause there can be multiple variants of test commands like you created in the previous step i.e
test:selective_unit_test. You can also create more variants e.g
test:bdd_testetc. You can combine all the variants together and run in a single command i.e
analyzein all the packages:
Create the following command under the script section:
Nothing fancy here. You can execute
melos run analyze to run the
analyze in all the packages.
d. Generating code coverage of the whole project:
To generate the code coverage for the whole project. There is a custom script included in the project i.e
combine_coverage.sh . This will basically merge all the
lcov.info files from different packages into one
lcov.info file. Then you can use this method to convert
lcov.info file to HTML.
Write the following command under the script section:
MELOS_ROOT_PATH will give you the path where
melos.yaml is stored i.e root project. After the script’s execution has been completed. You can see the
coverage_report folder in the project. Now you have one
lcov.info file which will give you a report of the whole project.
melos.yaml file will look something like this:
If you don’t want to execute these commands through the terminal and want to run them using GUI then Melos got you covered. After adding all the commands you can run the bootstrap command again. This will generate some configuration and you can see some GUI options like this:
Now you can execute all these commands without typing anything in the terminal. 😄
This is just the tip of the iceberg. You can learn much more filtering options and commands from the Melos website. Hope you enjoyed the article. Please do connect with me on Twitter and LinkedIn. Stay safe and stay healthy. 😃