Monorepo avec JavaScript : organisation du code en pratique
\n\nLe développement de projets complexes en JavaScript (Node.js) est souvent confronté au problème de la gestion du code. Lorsque vous avez plusieurs packages, bibliothèques ou microservices, chacun vivant dans son propre dépôt, cela entraîne une duplication du code, des difficultés de synchronisation des versions et un ralentissement du CI/CD. La solution est le monorepo. Dans cet article, nous allons voir comment organiser un monorepo avec JavaScript en pratique : du choix des outils à la configuration de la construction et de la publication.
\n\nQu'est-ce qu'un monorepo et pourquoi en a-t-on besoin ?
\n\nUn monorepo est une approche de gestion du code où tous les packages, bibliothèques et applications du projet sont stockés dans un seul dépôt. Contrairement aux multi-repos (chaque package dans son propre dépôt), le monorepo propose :
\n\n- \n
- Un historique unique des modifications : facile à suivre comment les changements dans une partie affectent une autre. \n
- La réutilisation du code : les utilitaires et composants communs vivent au même endroit sans publication sur npm. \n
- Un refactoring simplifié : la modification de l'API d'un package est immédiatement visible dans tous les dépendants. \n
- Des paramètres CI/CD unifiés : un seul fichier de configuration pour tous les packages. \n
Pour JavaScript (Node.js), le monorepo est particulièrement pertinent car il permet de se débarrasser de « l'enfer des dépendances » et d'accélérer le développement. Examinons une mise en œuvre pratique.
\n\nOutils pour le monorepo en JavaScript
\n\nIl existe plusieurs outils populaires sur le marché. Nous allons en examiner deux principaux : npm workspaces (intégré à npm) et Lerna (fonctionnalités avancées).
1. npm workspaces (support intégré)
\n\nDepuis npm v7, le gestionnaire de packages prend en charge les workspaces. C'est le moyen le plus simple de commencer. Exemple de structure de projet :
\n\nmy-monorepo/\n├── packages/\n│ ├── core/\n│ │ ├── package.json\n│ │ └── index.js\n│ ├── utils/\n│ │ ├── package.json\n│ │ └── helpers.js\n│ └── app/\n│ ├── package.json\n│ └── server.js\n├── package.json\n└── lerna.json (optionnel)\n\npackage.json racine :
{\n "name": "my-monorepo",\n "private": true,\n "workspaces": ["packages/*"]\n}\n\nDésormais, tous les packages dans packages/* sont automatiquement liés. Pour installer les dépendances, il suffit d'exécuter npm install à la racine. Les dépendances entre packages sont spécifiées de manière standard :
// packages/app/package.json\n{\n "name": "@my/app",\n "dependencies": {\n "@my/core": "*",\n "@my/utils": "*"\n }\n}\n\nnpm workspaces crée des liens symboliques dans le dossier node_modules, donc les imports fonctionnent comme avec des packages normaux.
2. Lerna (gestion avancée)
\n\nLerna est un outil de gestion des monorepos avec des capacités de publication, de versionnage et d'exécution de scripts en parallèle. Installation :
\n\nnpm install --global lerna\n\nInitialisation dans le projet :
\n\nlerna init\n\nFichier lerna.json :
{\n "version": "independent",\n "npmClient": "npm",\n "packages": ["packages/*"]\n}\n\nLe mode independent permet à chaque package d'avoir sa propre version. Commandes principales :
- \n
lerna bootstrap— installe les dépendances et lie les packages. \n lerna run build— exécute le scriptbuilddans tous les packages. \n lerna publish— publie les packages modifiés sur npm. \n
Organisation pratique du code
\n\nExaminons un exemple de configuration d'un monorepo pour une application web avec un backend en Node.js et des utilitaires communs.
\n\nÉtape 1 : Structure de base
\n\nCréons trois packages :
\n\n