This repository is a collection of packages and best practices.
We like to keep our dependencies to a minimum and make as much use of the libraries or packages that we install. This guide will walk you through some of the packages and explain why we are using them.
We are using FVM (flutter version manager) to ensures that every developer uses the same flutter sdk. FVM does a great job in managing your different flutter sdks and sharing them across your projects.
To install fvm
:
- Run
dart pub global activate fvm
- Run
fvm version
to check if the installation was successful. - Run
fvm install
. This will install the SDK and link it with the project. This link can be found in.fvm/flutter_sdk
. - Run
fvm flutter doctor
to ensure your setup is correct. - If needed link the installed SDK with your IDE. See https://fvm.app/docs/getting_started/configuration
fvm
but you can not find the .fvm/flutter_sdk
link to the flutter sdk, you need to
call fvm install
. You should now see .fvm/flutter_sdk
.
More details here: https://fvm.app/docs/getting_started/overview
Please ensure that the sdk is set up correctly by calling fvm flutter doctor
We use Riverpod for state management. Riverpods provides all the tools we need to build different kinds of architectures for different apps in a simple way.
As explained above, we are trying to keep our package dependencies to a minimum and that's why we also use Riverpod for
dependency injection.
We can override providers when creating a ProviderContainer
and this gives us the ability to mock certain providers
in a test.
We might setup our provider structure like this:
// Here we have a simple service that is wrapped in a provider.
final provMyService = Provider<MyService>((ref) => MyServiceImpl());
final provHomeChangeNotifier = ChangeNotifierProvider((ref) {
// Accessing dependencies is done like this.
// Based on your use case you might use ref.watch().
return HomeChangeNotifier(myService: ref.read(myService));
});
In a test scenario we can simply mock MyService
like this:
void main() {
test("example test", () {
final container = ProviderContainer(
overrides: [
provMyService.overrideWithValue(MyServiceMock()),
],
);
final homeChangeNotifier = container.read(provHomeChangeNotifier);
});
}
CI/CD is part of every application we build at tapped. Independent of the platform executing the pipeline (mostly GitHub or GitLab) most projects configure the pipeline to do 4 basics tasks that can be grouped in different stages.
Static code analysis will catch compile time errors and warnings.
It can be executed in the project directory by using fvm flutter analyze
.
It's important to have a consistent formatting in every file. Especially widgets have bigger build methods that
suffer from readability when reading changes in a diff.
Keeping a consistent formatting helps reading diffs and avoids arguing about code style.
Running the formatter in the pipeline can be done by executing fvm flutter format --set-exit-if-changed
.
This will also reformat generated code. We can adjust our code to exclude generated code.
find . -name "*.dart" ! -name "*.g.dart" ! -name "*.freezed.dart" ! -path '*/generated/*' ! -path '*/gen/*' | xargs fvm flutter format -n --set-exit-if-changed
Execute tests using fvm flutter test
TODO talk about deployment using fastlane if needed.
Right now the packages are not published to pub and adding them is done using the git
keyword.
dependencies:
tapped_toolkit:
git:
url: git@github.com:tappeddev/tapped_toolkit.git
ref: stable