Comment Node.js traite les arguments de ligne de commande : de process.argv aux sources
\n\nImaginez : vous avez écrit un super script Node.js qui convertit des images. Mais devoir modifier le code à chaque fois pour spécifier le nom du fichier, c'est dépassé. Il est bien plus cool de lancer : node convert.js --input photo.jpg --format webp et d'obtenir le résultat. Comment réaliser cette magie ? C'est exactement à cette question, l'une des plus populaires sur Stack Overflow, que nous allons consacrer du temps aujourd'hui.
Cela semble simple, non ? Mais sous le capot de Node.js (et de V8 lui-même) se cachent plusieurs couches qu'il est utile de connaître pour chaque développeur. Nous ne montrerons pas seulement comment obtenir process.argv — nous plongerons dans le code source de Node.js et découvrirons comment les arguments voyagent de votre terminal aux variables d'environnement du processus. C'est parti !
Pourquoi les arguments de ligne de commande sont-ils nécessaires ?
\nLes arguments de ligne de commande (CLI arguments) sont le principal moyen de rendre votre programme flexible et réutilisable sans modifier le code. Au lieu de coder en dur, vous transmettez des données en entrée. C'est la base de presque tous les outils DevOps, les bundlers (Webpack, Vite) et les utilitaires. Savoir les utiliser est une compétence fondamentale pour tout développeur JavaScript souhaitant sortir du cadre du navigateur.
\n\nNiveau 1 : Les bases — process.argv
\nLa manière la plus simple et native d'obtenir des arguments dans Node.js est d'accéder à l'objet global process.argv. C'est un tableau de chaînes de caractères. Voyons tout de suite un exemple.
Fichier : args-demo.js
\n// args-demo.js\nconsole.log(process.argv);\n\nLançons-le avec des arguments :
\nnode args-demo.js hello --name=World 42\n\nSortie console :
\n[\n '/usr/local/bin/node', // 0 : chemin vers l'exécutable Node.js\n '/home/user/args-demo.js', // 1 : chemin vers votre script\n 'hello', // 2 : premier argument utilisateur\n '--name=World', // 3 : deuxième argument\n '42' // 4 : troisième argument\n]\n\nVoilà toute la magie. process.argv est simplement une copie de ce que le système d'exploitation a transmis au processus. Les deux premiers éléments sont des informations système. Tout ce qui vient après l'index 2 correspond à vos arguments. Important : ce sont tous des chaînes de caractères. Le nombre 42 est arrivé sous forme de chaîne "42".
Comment ignorer les deux premiers éléments ?
\nPour plus de commodité, on utilise souvent la déstructuration :
\n// On obtient uniquement les arguments utilisateur\nconst [, , ...userArgs] = process.argv;\nconsole.log(userArgs); // ['hello', '--name=World', '42']\nOu simplement process.argv.slice(2).
Niveau 2 : Analyse manuelle — votre propre solution
\nTravailler avec un tableau brut de chaînes n'est pas pratique. Nous devons distinguer les flags (--name) des valeurs (World). Écrivons un analyseur simple pour comprendre la logique.
// simple-parser.js\nconst args = process.argv.slice(2);\nconst parsed = {};\n\nfor (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg.startsWith('--')) {\n // On enlève '--' et on cherche la valeur\n const key = arg.slice(2);\n const next = args[i + 1];\n // Si l'argument suivant ne commence pas par '--', c'est une valeur\n if (next && !next.startsWith('--')) {\n parsed[key] = next;\n i++; // On saute l'étape d'itération suivante\n } else {\n parsed[key] = true; // Flag booléen\n }\n } else if (arg.startsWith('-')) {\n // Flags courts, par exemple -v\n const key = arg.slice(1);\n parsed[key] = true;\n } else {\n // Argument positionnel simple\n if (!parsed._) {\n parsed._ = [];\n }\n parsed._.push(arg);\n }\n}\n\nconsole.log(parsed);\n// node simple-parser.js --name World -v hello\n// { name: 'World', v: true, _: ['hello'] }\n\nCe code est la base de bibliothèques comme minimist. Comme vous le voyez, rien de compliqué. Mais dans des projets réels, il est préférable d'utiliser des solutions prêtes à l'emploi