Linting Tools in Flutter: A Complete Guide
1. Introduction to Linting
Linting helps ensure that your code adheres to defined coding standards and best practices. It
analyzes your code to catch potential errors, enforce stylistic conventions, and maintain code
quality.
2. Basic Setup and Configuration
2.1. Creating a Flutter Project
To start, create a new Flutter project if you haven’t already:
flutter create my_flutter_project
cd my_flutter_project
2.2. Adding Linting Dependencies
Linting in Flutter is typically handled using the flutter_lints or lint package.
2.2.1. Using flutter_lints
1. Open pubspec.yaml and add flutter_lints under dev_dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0 # Use the latest version
2. Run:
flutter pub get
2.2.2. Using lint
1. Open pubspec.yaml and add lint under dev_dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
lint: ^2.0.0 # Use the latest version
2. Run:
flutter pub get
2.3. Configuring Linting Rules
Create or modify analysis_options.yaml in the root of your Flutter project to configure
linting rules.
2.3.1. Basic Configuration
For flutter_lints:
include: package:flutter_lints/flutter.yaml
For lint:
include: package:lint/analysis_options.yaml
2.4. Running the Linter
Execute the following command to analyze your code:
flutter analyze
This will run the linter based on the rules defined in analysis_options.yaml.
3. Intermediate Configuration
3.1. Customizing Linting Rules
You can customize or override existing linting rules in analysis_options.yaml.
Example configuration:
include: package:flutter_lints/flutter.yaml
linter:
rules:
always_declare_return_types: true
avoid_print: true
prefer_const_constructors: true
unnecessary_import: true
avoid_unnecessary_containers: true
prefer_final_fields: true
prefer_single_quotes: true
always_put_control_body_on_new_line: true
avoid_function_literals_in_foreach_calls: true
sort_constructors_first: true
avoid_renaming_method_parameters: true
prefer_is_empty: true
3.2. Integrating with IDEs
Most IDEs provide integrated support for linting:
3.2.1. Visual Studio Code (VSCode)
Install the Dart and Flutter extensions.
Linting will be automatically applied based on your analysis_options.yaml.
3.2.2. IntelliJ IDEA
Install the Dart and Flutter plugins.
Linting will be automatically applied based on your analysis_options.yaml.
3.3. Continuous Integration (CI)
To enforce linting rules in your CI/CD pipeline, add linting checks to your CI configuration.
Example: GitHub Actions
Create a workflow file, e.g., .github/workflows/ci.yml:
name: Flutter CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Flutter
uses: subosito/flutter-action@v3
with:
flutter-version: 'latest'
- name: Get dependencies
run: flutter pub get
- name: Analyze
run: flutter analyze
4. Advanced Configuration
4.1. Creating Custom Linting Rules
You can create custom linting rules by defining your own rules in a Dart package.
4.1.1. Create a Dart Package
1. Create a new Dart package:
dart create --template=package my_custom_lint_rules
cd my_custom_lint_rules
2. Add analyzer as a dependency in pubspec.yaml:
dependencies:
analyzer: ^4.0.0 # Use the latest version
3. Define custom rules in lib/src/my_custom_rules.dart:
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/lint/lint.dart';
class CustomLintRule extends LintRule {
CustomLintRule()
: super(
name: 'custom_lint_rule',
description: 'Custom lint rule description.',
details: 'Details about the custom lint rule.',
group: Group.style,
);
@override
LintRuleVisitor createVisitor() => _Visitor(this);
}
class _Visitor extends SimpleAstVisitor<void> {
final LintRule rule;
_Visitor(this.rule);
@override
void visitMethodInvocation(MethodInvocation node) {
if (node.methodName.name == 'print') {
rule.reportLint(node);
}
}
}
4. Export the rule in lib/my_custom_lint_rules.dart:
export 'src/my_custom_rules.dart';
5. Publish the package locally:
sh
Copy code
dart pub publish --dry-run
4.2. Integrating Custom Rules
1. Add the custom linting package to pubspec.yaml:
dev_dependencies:
flutter_test:
sdk: flutter
my_custom_lint_rules:
path: ../path_to_my_custom_lint_rules
2. Update analysis_options.yaml to include your custom rules:
include: package:flutter_lints/flutter.yaml
linter:
rules:
always_declare_return_types: true
avoid_print: true
prefer_const_constructors: true
unnecessary_import: true
avoid_unnecessary_containers: true
prefer_final_fields: true
prefer_single_quotes: true
always_put_control_body_on_new_line: true
avoid_function_literals_in_foreach_calls: true
sort_constructors_first: true
avoid_renaming_method_parameters: true
prefer_is_empty: true
custom_lint_rule: true # Your custom rule
4.3. Testing and Maintaining Custom Rules
Run Linter: Use flutter analyze to test custom linting rules.
Document Rules: Provide clear documentation on what each custom rule does.
Update: Regularly update and maintain your custom rules as your project evolves.
5. Best Practices
Consistency: Ensure linting rules are consistent across your team.
Automation: Integrate linting into CI/CD pipelines to enforce standards
automatically.
Documentation: Keep documentation updated for both custom and built-in linting
rules.
6. Additional Resources
Flutter Lints GitHub Repository: flutter_lints
Lint Package GitHub Repository: lint
Enforcing Folder Structure in a Flutter
Project
Introduction
In Flutter development, maintaining a consistent folder structure is crucial for the scalability,
maintainability, and readability of the codebase. However, Flutter's default linting tools don't
directly enforce folder structures. This guide will walk you through setting up custom linting
rules, scripts, and CI/CD processes to ensure your Flutter project follows a well-organized
folder structure.
Table of Contents
1. Recommended Folder Structure for Flutter Projects
2. Using custom_lint to Create Custom Linting Rules
o Installing custom_lint
o Creating Custom Lint Rules
o Running Custom Lint Rules
3. Folder Structure Validation with Scripts
o Shell Script Approach
o Running the Script in CI/CD
4. Integrating Folder Structure Validation in CI/CD
5. Best Practices for Enforcing Folder Structure
6. Conclusion
1. Recommended Folder Structure for Flutter Projects
To maintain consistency and organization, the following folder structure is recommended for
Flutter projects:
lib/
│
├── src/
│ ├── models/ # Data models and entities
│ ├── services/ # API calls, data fetching, and business
logic
│ ├── widgets/ # Reusable widgets and UI components
│ ├── screens/ # Screens for different parts of the app
│ ├── providers/ # State management classes (if using Provider
or similar)
│ └── utils/ # Utility classes, constants, and helpers
│
├── assets/
│ ├── images/ # Image assets
│ ├── fonts/ # Font files
│ └── icons/ # Icon assets
│
├── localization/ # Language files and localization logic
│
├── theme/ # App theme-related files (colors, text
styles, etc.)
│
├── routes/ # Routing and navigation setup
│
└── main.dart # Entry point of the app
This structure helps keep the project organized and easy to navigate, especially as the app
grows in complexity.
2. Using custom_lint to Create Custom Linting Rules
A. Installing custom_lint
To start creating custom linting rules, you need to install the custom_lint package. Add it to
your pubspec.yaml file under dev_dependencies:
dev_dependencies:
custom_lint: ^0.3.0 # Check for the latest version
Then, run the following command to install the package:
bash
Copy code
flutter pub get
B. Creating Custom Lint Rules
Custom lint rules allow you to enforce specific patterns in your code, including file
placement. Below is an example of creating a custom lint rule that enforces that files
containing "model" in their name are placed in the src/models/ directory.
1. Create a Dart file for the custom lint:
Create a new Dart file under lib/lints or any other directory of your choice. For
example, lib/lints/folder_structure_lint.dart.
2. Define the custom lint rule:
Here’s an example of a simple custom lint rule:
import 'package:custom_lint/custom_lint.dart';
class FolderStructureLintRule extends LintRule {
@override
LintCode get code => LintCode('folder_structure_lint', "File should
be in a specific folder");
@override
void check(LintCodeCheckContext context) {
final filePath = context.filePath;
// Example: Enforce that all files containing "model" are in the
models folder
if (filePath.contains('model') && !filePath.contains('/models/'))
{
context.reportError(code, "Model files should be placed in the
'models' directory.");
}
}
}
class FolderStructureLintPlugin extends LintPlugin {
@override
List<LintRule> getLintRules() => [FolderStructureLintRule()];
}
LintPlugin registerLintPlugin() => FolderStructureLintPlugin();
3. Enable the custom lint rule:
To activate your custom lint, create a custom_lint.yaml file in the root of your
project:
enabled_lints:
- folder_structure_lint
C. Running Custom Lint Rules
Run the custom lint rules using the following command:
flutter pub run custom_lint
This will analyze your project and report any violations based on the custom rules you've
defined.
3. Folder Structure Validation with Scripts
If you prefer a simpler approach or want to complement custom linting with additional
checks, you can use shell scripts to validate the folder structure.
A. Shell Script Approach
Create a script that checks whether certain files are in the correct directories. For example:
#!/bin/bash
# Array of expected directories
directories=("lib/src/models" "lib/src/services" "lib/src/widgets")
# Loop through directories and check if they exist
for dir in "${directories[@]}"; do
if [ ! -d "$dir" ]; then
echo "Error: $dir directory is missing!"
exit 1
fi
done
# Additional checks for file placement
for file in $(find lib/ -type f -name '*model.dart'); do
if [[ "$file" != *"src/models/"* ]]; then
echo "Error: Model file $file is not in the 'src/models/' directory!"
exit 1
fi
done
echo "Folder structure validated successfully!"
B. Running the Script in CI/CD
You can include this script in your CI/CD pipeline to automatically check the folder structure
during builds or before merging code.
4. Integrating Folder Structure Validation in CI/CD
Integrating folder structure validation into your CI/CD pipeline ensures that all code follows
the established structure before it gets merged or deployed.
Here’s an example using GitHub Actions:
name: Validate Folder Structure
on: [push, pull_request]
jobs:
check_structure:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Validate Folder Structure
run: ./validate_structure.sh # Run your custom script
This pipeline will run the validate_structure.sh script on every push or pull request,
ensuring the folder structure is correct.
5. Best Practices for Enforcing Folder Structure
Documentation: Clearly document the expected folder structure and file placement
rules in your project’s README or a separate CONTRIBUTING.md file.
Code Reviews: Make folder structure a part of your code review process. Reviewers
should check that new files are placed in the correct directories.
IDE Integration: Use IDE templates or snippets to generate files in the correct
directories automatically.
Automation: Automate folder structure checks using scripts or CI/CD pipelines to
enforce rules consistently across your team.