Set up a mono repository
Table of contents
- Create project folder
- Go to the project folder
- Initialize git
- Create packages folder
- Change to packages folder
- Create app project
- Change to app folder
- Commit .gitignore
- Commit .gitignore
- Commit Flutter project
- Init fvm for project
- Change .gitignore for FVM
- Change demo_mono_repo_app.iml
- Commit FVM changes
- Remove android.iml from modules.xml
- Commit modules.xml
- Mono repo setup is finished
- Make all these steps a one-liner
- Always open the app folder
I was intrigued by a blog post from Rémi Rousselet with the title Getting started: Creating your Flutter project. In this post, Rémi does an excellent job in explaining how to set up a Flutter project with the right rules, like enabling strong-mode, set up the linter, and disable warnings for generated files. A great way to start…. except for one thing, that I could not grasp fully. Rémi advises using the ‘/packages’ folder convention. Although I did understand the idea behind it, I could not find the right workflow to set this up. It always felt a bit like hacking and abusing the IDE, in my case Android Studio, until it worked.
In this blog post, I write about the workflow that I have found to set this up the right way, and with consistent results. ‘Consistent result’ you might think…. what? This is because Android Studio does more than just opening the folder when you open a Flutter project for the first time. It does search and index the whole tree and makes assumptions about how you probably want to use the project. It uses the data and file contents (like .gitignore) in your project folder, to guess the right settings. This means that if you do things in (a slightly) different order, the result is a bit different.
This blog post will help you to set up your Flutter project consistently and logically. You will have Flutter app project, with the possibility to extract your reusable code in separate packages (or plugins). With, of course, the ability to reuse these packages easily in other projects. You could even put these packages later on at pub-dev, and just update the reference in pubspec.yaml to use the published version.
There is also a companion repository on github to automate this process. You can read about it here: Make all these steps a one-liner
I use Flutter Version Management (FVM) by Leo Farias. If you have multiple Flutter projects that you have to support, this tool is mandatory. It keeps track of the Flutter version you have used for a specific project and it makes switching between these versions a breeze. You will never have to wait again for downloading the Flutter files when you switch to another project that uses another version of Flutter. It will improve your life as a developer.
Make sure you have FVM installed and applied the setup of paragraph “Set Global Version”.
Create project folder
I use the following convention for the project folder:
The customer id filled up with zeros to seven positions. Companies might change their name, but their id (as used in the ERP or financial system) does not change.
A separator between customer id and app name.
This is the name of the app, only lowercase and underscores allowed
A separator between app name and the company name
This is the name of the company, this makes it easy to search for a project in a folder
Go to the project folder
You can also enable git via Android Studio:
Menu => VCS => Enable Version Control Integration…
But this does create a .git folder inside the Flutter project. This is not what we want. The goal is to have a mono-repo, which means multiple packages in one git repository. That’s why we have to do the git init in the top project folder
Create packages folder
Change to packages folder
Create app project
fvm flutter create --org rubigo --project-name demo_mono_repo_app --ios-language objc --android-language java app
This is the Flutter Version Management program.
Because of FVM’s “Set Global Version”, the selected Flutter version will be used to execute the command.
This instructs Flutter to create a new app project
- –org com.rubigo
The company to use. This is used (with the project name) for Android’s application id and iOS’s product bundle identifier.
- –project-name demo_mono_repo_app
This is the name of the app, only lowercase and underscores are allowed. I keep this identical to the name of the app in the project folder name.
- –ios-language objc
It’s my preference to use objective c as the language for the iOS runner. Choose as you like.
- –android-language java
It’s my preference to use java as the language for the Android runner. Choose as you like.
This is the name of the folder for the app project that is created inside the packages folder. If it’s always ‘app’ across projects then it’s always easy to find.
Change to app folder
git add .gitignore git commit -m "[app] Initial commit"
Because we will edit the gitignore file, we will commit it first to have a complete history correct.
Change .gitignore for IntelliJ IDEA
# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.idea/**/libraries
The new .gitignore allows sharing of modules and run configurations between developers.
git add .gitignore git commit -m "[app] Change .gitignore to include important .idea files"
The changes are committed.
Commit Flutter project
git add -A git commit -m "[app] Initial flutter project"
Now the freshly created Flutter project is committed.
Init fvm for project
fvm use 1.22.6
This adds the .fvm folder to the project. This folder contains a file with the flutter version to use and a symlink to the selected Flutter version.
Change .gitignore for FVM
# FVM related /.fvm/flutter_sdk
These lines are needed to explicitly exclude the flutter_sdk folder from git. Otherwise, you have the risk of adding a complete Flutter SDK to your repository.
<content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/lib" isTestSource="false"/> <sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true"/> <excludeFolder url="file://$MODULE_DIR$/.dart_tool"/> <excludeFolder url="file://$MODULE_DIR$/.fvm/flutter_sdk"/> <excludeFolder url="file://$MODULE_DIR$/.idea"/> <excludeFolder url="file://$MODULE_DIR$/.pub"/> <excludeFolder url="file://$MODULE_DIR$/build"/> </content>
This excludes the flutter_sdk path in Android Studio. Otherwise, search results will also include results in the Flutter SDK.
If you try to add this line via the Android Studio menus File=>Project Structure=>Modules, Android Studio will bite you. During startup, all folders are indexed, including the .fvm/flutter_sdk folder. You will end up with countless excluded folders from the SDK folder in the demo_mono_repo_app.iml file.
Commit FVM changes
git add -A git commit -m "[app] Init FVM 1.22.6"
Remove android.iml from modules.xml
<modules> <module fileurl="file://$PROJECT_DIR$/demo_mono_repo_app.iml" filepath="$PROJECT_DIR$/demo_mono_repo_app.iml" /> -- <module -- fileurl="file://$PROJECT_DIR$/android/demo_mono_repo_app_android.iml" -- filepath="$PROJECT_DIR$/android/demo_mono_repo_app_android.iml" /> </modules>
Remove the demo_mono_repo_app_android.iml module in the file .idea/modules.xml. It is not needed.
git add -A git commit -m "[app] Remove demo_mono_repo_app_android.iml from modules.xml"
Mono repo setup is finished
This is it, the flutter mono repo is successfully set up.
Make all these steps a one-liner
If you want to make these steps above a one-liner you can use this dart cli project: https://github.com/jsroest/create_flutter_mono_repo
dart create_flutter_mono_repo.dart --root-path /<your repos folder> --customer-id 0000000 --project-name demo_mono_repo_app --customer-name rubigo --org com.example --ios-language objc --android-language java --flutter-version 1.22.6
Always open the app folder
Remember to always open the app folder in Android Studio if you want to work on your Flutter app or one of the local packages that you will add later. The app folder will contain links to the other packages so that you can edit all your Flutter code from one place.