Outils CLI
Règles
- Commander.js pour l'analyse des arguments —
.command(), .option(), .argument() avec descriptions
- Invites interactives :
@clack/prompts (moderne, esthétique) ou inquirer — pour la saisie utilisateur quand les arguments ne sont pas fournis
- Spinners :
ora pour les opérations longues — démarrer, mettre à jour le message, réussite/échec
- Couleurs :
chalk pour un affichage stylisé — à utiliser avec parcimonie : rouge pour les erreurs, vert pour les succès, jaune pour les avertissements, grisé pour les informations secondaires
- Fichiers de configuration :
cosmiconfig — recherche automatiquement .toolrc, .toolrc.json, tool.config.js, clé dans package.json
- Codes de sortie :
0 pour succès, 1 pour erreur générale, 2 pour erreur d'utilisation — toujours process.exit(code)
- Indicateurs
--help et --version : Commander les ajoute automatiquement — écrire des descriptions claires pour chaque option
- Gestion des erreurs : capturer les erreurs au niveau supérieur, afficher un message convivial sur stderr, quitter avec le code 1
- Publication : champ
bin dans package.json, shebang #!/usr/bin/env node, "type": "module" pour ESM
Modèles
#!/usr/bin/env node
import { Command } from "commander";
import * as p from "@clack/prompts";
import ora from "ora";
import chalk from "chalk";
const program = new Command()
.name("my-tool")
.description("Un CLI qui fait des choses utiles")
.version("1.0.0");
program
.command("init")
.description("Initialiser un nouveau projet")
.option("-t, --template <name>", "modèle à utiliser", "default")
.action(async (options) => {
p.intro(chalk.bold("Configuration du projet"));
const name = await p.text({ message: "Nom du projet ?", placeholder: "my-app" });
if (p.isCancel(name)) { p.cancel("Annulé."); process.exit(0); }
const spinner = ora("Création du projet...").start();
await createProject(name, options.template);
spinner.succeed(chalk.green("Projet créé !"));
p.outro(`Exécutez ${chalk.cyan(`cd ${name} && npm install`)}`);
});
program.parse();
Éviter
- Imprimer les erreurs sur stdout — utiliser
console.error() ou process.stderr.write() pour les erreurs
- Quitter sans code en cas d'échec — toujours
process.exit(1) pour que les scripts et l'IC détectent l'échec
- Murs de texte non formaté — utiliser les couleurs chalk, les sections et les espaces pour la lisibilité
- Exiger une saisie interactive sans alternative par indicateur — toujours supporter les remplacements
--flag pour l'IC/scripting
- Oublier le shebang
#!/usr/bin/env node — sans lui, npx et les installations globales ne fonctionneront pas