Flutter Coding Environment: FVM + Melos + Happiness

Matheus Lopes
4 min readApr 26, 2023

--

So…

I started to learn about Dart & Flutter a couple of months ago, and I got to a point that two things become hard:

  1. Manage flutter versions
  2. Execute dart/flutter commands in different packages in the same project

After some researching, and talking with some friends, I was introduced to:

  1. FVM (i.e. flutter version manager)
  2. Melos (i.e. CLI tool used to help manage Dart projects with multiple packages (also known as mono-repos))

And bellow is how I did my first setup, trying to cover:

  1. get dependencies
  2. tests
  3. test coverage reports
  4. files generation (e.g. .g.dart, .freezed.dart)
  5. lint

Of course that those tools can help with another things, but lets do one step at time, right?

Requirements

I’m assuming that you:

  1. Are using some Linux OS
  2. have brew package manager installed

Starting with FVM:

To install, run:

brew tap leoafarias/fvm
brew install fvm

Plus, to use FVM as a global flutter version manager, I ran:

dart pub global activate fvm

At this point, we can verify some cool things, like:

  1. Check available to download flutter versions, running:
fvm releases

output should be like:

A bash terminal output with some flutter releases, showing date and version number

Suppose your new flutter project will use a Flutter 3.7.9 version. You should get this version using fvm like:

fvm install 3.7.9

After the downloads ends successfully, you can, inside de project folder, execute:

fvm use 3.7.9

That command will create a folder (in the root project) called .fvm/ with the selected flutter version.

vscode tip:

If you are using VSCode, you can add this settings to help the IDE find Flutter and Dart SDK’s paths.

In the root project, create a .vscode folder, inside this folder, create a settings.json file with:

{
"dart.flutterSdkPath": ".fvm/flutter_sdk",
// Remove .fvm files from search
"search.exclude": {
"**/.fvm": true
},
// Remove from file watching
"files.watcherExclude": {
"**/.fvm": true
}
}

As you can see, this configuration also remove .fmv files from search and watching changes.

Finally

You are able to run any flutter command using ‘fvm’ that assure the run with the selected version, e.g.:

## resolve dependencies 
fvm flutter pub get

## run or any other flutter command
fvm flutter run

Pretty nice, right?

So now, if you have any other flutter project, with a different version, you can use those steps above to make a fvm setup, and then run a fvm flutter something.

ps: please don’t forget to add the .fvm/ folder in your .gitignore file.

And Now, Melos:

I don’t know how proficient you are in Dart & Flutter development, but to me sounds sad whenever I need to execute any command (e.g tests, lint etc) because I manually need to enter inside the package folder, or create a strange .sh script or even a makefile.

So Melos hugs me like a mother hugs, because now I don’t need to care about how many packages exists.

Btw, in a mono-repo point of view, Melos should be a must have approach.

Anyway, starting from beginning.

dart pub global activate melos
  1. At my root project I created a melos.yaml file with:
### just the project name
name: vinttem_app

# here we can track where Melos should look to execute it scripts
packages:
- .
- packages/*

# and overhere, we have commands
scripts:
qualitycheck:
run: |
melos run clean && \
melos run get

clean:
run: melos exec -c 1 -- \
fvm flutter clean

get:
run: melos exec -c 1 -- \
fvm flutter pub get

lint:all:
run: melos run analyze
lint:
run: melos exec -c 1 -- \
fvm dart analyze .
description: |
Run `dart analyze` in all packages.
- Note: you can also rely on your IDEs Dart Analysis / Issues window.

test:all:
run: melos run test
test:
run: melos exec -c 1 -- \
fvm flutter test --coverage --test-randomize-ordering-seed random
generate_coverage:
run: melos exec -c 1 -- \
"\$MELOS_ROOT_PATH/combine_coverage.sh"

build_runner:all:
run: melos run build_runner
build_runner:
run: melos exec -c 1 -- \
fvm flutter pub run build_runner build --delete-conflicting-outputs

ps: Some commands have -c 1 (that is concurrency = 1) so then each package finish the execution to start other. I did this because I heard that’s better for github-actions machines execution.

2. Then add melos as a dev-dependency:

dart pub add melos --dev

3. Update .gitignore with:

## if you have added, remove .pubspec.lock
.pubspec.lock ## <-- remove this

## add this one (because melos will gerenate overrides pubspec's, but we don't need to commit)
pubspec_overrides.yaml

4. Now, we just need to run melos bootstrap command to install all packages and locally link packages:

melos bootstrap

5. Finally, if you run for example the lint script?

melos run lint

The output should be something like this:

A melos output saying that all lint packages runs successfully

It’s pretty much this.

Now is possible change across flutter versions and manage multi-packages & mono-repos in a smooth way.

Btw, here you can see a personal repo of mine using melos + fvm: https://github.com/theusindabike/vinttem_app

--

--