dart-cli-app-best-practices

Meilleures pratiques pour créer des applications CLI Dart de haute qualité et exécutables. Couvre la structure du point d'entrée, la gestion des codes de sortie et les packages recommandés.

npx skills add https://github.com/flutter/skills --skill dart-cli-app-best-practices

Bonnes pratiques pour applications Dart CLI

1. Quand utiliser cette compétence

Utilisez cette compétence quand :

  • Vous créez une nouvelle application Dart CLI.
  • Vous refactorisez un point d'entrée CLI existant (bin/).
  • Vous examinez du code CLI pour la qualité et les standards.
  • Vous configurez des scripts exécutables pour Linux/Mac.

2. Bonnes pratiques

Structure du point d'entrée (bin/)

Gardez le contenu de votre fichier point d'entrée (p. ex. bin/my_app.dart) minimal. Cela améliore la testabilité en découplant la logique du processus exécuteur.

À FAIRE :

// bin/my_app.dart
import 'package:my_app/src/entry_point.dart';

Future<void> main(List<String> arguments) async {
  await runApp(arguments);
}

À NE PAS FAIRE :

  • Mettre une logique complexe directement dans bin/my_app.dart.
  • Définir des classes ou des fonctions lourdes au point d'entrée.

Ajouter une entrée executables dans pubspec.yaml

Listez vos exécutables dans pubspec.yaml pour les rendre disponibles pour l'activation globale et l'invocation propre via dart run.

À FAIRE : Ajoutez une section executables qui associe le nom de la commande au fichier Dart dans bin/ (en excluant l'extension .dart).

executables:
  my_app: # Maps to bin/my_app.dart
  custom_name: main # Maps to bin/main.dart

Exécutez ensuite via dart run my_app ou dart run custom_name.

ENVISAGEZ #! pour d'autres scripts sur systèmes *nix

Ce n'est PAS une règle stricte, mais c'est quelque chose à considérer.

Pour les outils CLI destinés à être exécutés directement sur Linux et Mac, ajoutez un shebang et assurez-vous que le fichier est exécutable.

À FAIRE :

  1. Ajoutez #!/usr/bin/env dart à la première ligne.
  2. Exécutez chmod +x bin/my_script.dart pour rendre le fichier exécutable.
#!/usr/bin/env dart

void main() => print('Ready to run!');

Terminaison de processus (exitCode)

Gérez correctement la terminaison du processus pour permettre le débogage et la signalisation correcte du statut.

À FAIRE :

  • Utilisez le setter exitCode pour signaler une défaillance.
  • Laissez main se terminer naturellement.
  • Utilisez des codes de sortie standards (sysexits) pour plus de clarté (p. ex. 64 pour un mauvais usage, 78 pour des erreurs de configuration).
    • Voir la classe ExitCode de package:io ou la page man FreeBSD sysexits.
import 'dart:io';

void main() {
  if (someFailure) {
    exitCode = 64; // À FAIRE !
    return;
  }
}

À ÉVITER :

  • Appeler exit(code) directement, car cela termine immédiatement la VM, empêchant le débogage « pause on exit » et les blocs finally de s'exécuter.

Gestion des exceptions

Les exceptions non capturées définissent automatiquement un code de sortie non nul, mais vous devriez gérer les erreurs attendues avec élégance.

Exemple :

Future<void> main(List<String> arguments) async {
  try {
    await runApp(arguments);
  } catch (e, stack) {
    print('App crashed!');
    print(e);
    print(stack);
    exitCode = 1; // Explicitly fail
  }
}

Compatibilité multiplateforme (support Windows)

Lors de l'écriture d'applications CLI et de tests, assurez la compatibilité avec Windows :

  • Chemins : Évitez de coder en dur les séparateurs de chemins comme / car Windows utilise \. Utilisez p.join ou p.normalize de package:path pour construire des chemins portables.
  • Permissions de fichiers : Lors du test des erreurs de permission de fichiers, souvenez-vous que chmod n'est pas disponible sur Windows. Utilisez icacls sur Windows ou les bibliothèques de mock appropriées pour simuler les erreurs de permission. Ne sautez jamais les tests sur Windows simplement à cause de commandes de permission si un équivalent Windows existe.

Découverte

Pour trouver les domaines où appliquer ces bonnes pratiques :

Points d'entrée lourds

Inspectez les fichiers dans bin/ pour voir s'ils contiennent une logique qui devrait être dans lib/ :

  • Cible : Fichiers correspondant à bin/*.dart.

Terminaison directe de processus

Recherchez les appels à exit() au lieu de définir exitCode :

  • Regex : \bexit\(

Séparateurs de chemins codés en dur

Recherchez les / codés en dur dans les chaînes qui semblent être des chemins de fichiers :

  • Regex : ['"][^'"]+/[^'"]+['"] (Vérifiez le contexte car cela peut correspondre aux URLs).

3. Packages recommandés

Utilisez ces packages standard de la communauté appartenant à l'équipe Dart pour résoudre les problèmes CLI courants :

Catégorie Package recommandé Usage
Stack Traces package:stack_trace stack traces détaillées et plus propres
Arg Parsing package:args parsing standard des flags/options
Testing package:test_process tests d'intégration pour apps CLI
Testing package:test_descriptor fixtures du système de fichiers pour tests
Networking package:http client HTTP standard (n'oubliez pas user-agent !)
ANSI Output package:io gestion des couleurs et styles ANSI

4. Packages intéressants de la communauté

Catégorie Package recommandé Usage
Configuration package:json_serializable objets de configuration fortement typés
CLI Generation package:build_cli générer des parseurs arg à partir de classes
Version Info package:build_version injection automatique de version
Configuration package:checked_yaml parsing YAML précis avec numéros de ligne

5. Conventions

  • File Caching : Écrivez les fichiers en cache dans .dart_tool/[pkg_name]/.
  • User-Agent : Définissez toujours un en-tête User-Agent dans les requêtes HTTP, incluant les informations de version.

Skills similaires