Monorepo avec JavaScript : organisation du code et bonnes pratiques
Le développement moderne en JavaScript (Node.js) est souvent confronté au problème de la gestion du code dans les grands projets. Lorsque le nombre de microservices, de bibliothèques et d'applications augmente, les dépôts multi-modules traditionnels (Polyrepo) commencent à créer le chaos : duplication des configurations, difficultés de synchronisation des versions et CI/CD long. La solution — le monorepo. Dans cet article, nous allons voir comment organiser le code dans un monorepo en JavaScript, quels outils utiliser et comment éviter les erreurs typiques.
Qu'est-ce qu'un monorepo et pourquoi en a-t-on besoin ?
Un monorepo est une approche où tout le code du projet (plusieurs applications, bibliothèques, services) est stocké dans un seul dépôt. Contrairement à Polyrepo, où chaque composant vit dans son propre dépôt Git, le monorepo regroupe tout dans une structure unique.
Avantages du monorepo pour JavaScript :
- Version unique des dépendances — tous les packages utilisent les mêmes versions des bibliothèques, ce qui élimine les conflits.
- Réutilisation du code — les utilitaires et composants communs sont facilement importés entre les sous-projets sans publication sur npm.
- Commits atomiques — les modifications dans plusieurs packages peuvent être effectuées en un seul commit, ce qui simplifie la revue et le rollback.
- CI/CD simplifié — un seul pipeline pour tout le projet, mise en cache des builds et des tests.
Cependant, le monorepo a aussi des inconvénients : il exige une discipline stricte dans l'organisation du code et un choix judicieux des outils. Nous allons maintenant voir comment organiser la structure et quels outils utiliser.
Outils de gestion de monorepo dans Node.js
L'écosystème JavaScript propose plusieurs outils matures pour travailler avec un monorepo. Examinons les trois plus populaires :
1. Lerna
L'outil classique qui a longtemps été la norme. Lerna gère la publication des packages, le versioning et l'exécution de scripts dans tous les packages. Exemple de configuration lerna.json :
{ "version": "independent", "packages": ["packages/*"], "npmClient": "yarn"}La commande lerna bootstrap installe les dépendances pour tous les packages et les lie entre eux.
2. Nx (Nrwl)
Un outil plus moderne et puissant avec un système de mise en cache avancé, des graphes de dépendances et des générateurs de code. Nx supporte non seulement JavaScript, mais aussi TypeScript, Angular, React, Next.js. Exemple de commande pour créer une bibliothèque :
npx nx generate @nrwl/node:library my-lib --directory=sharedNx analyse automatiquement les dépendances et ne reconstruit que les packages modifiés.
3. Turborepo
Créé par Vercel, Turborepo se concentre sur la vitesse de build et la simplicité. Il utilise une mise en cache intelligente et l'exécution parallèle des tâches. Exemple de turbo.json :
{ "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] }, "test": { "dependsOn": ["build"], "outputs": [] } }}Turborepo est idéal pour les projets avec un grand nombre de packages où la vitesse du CI est importante.
Organisation de la structure du projet dans un monorepo
Une structure de dossiers correcte est la base d'un monorepo réussi. Examinons une structure typique pour un projet Node.js :
my-monorepo/├── packages/│ ├── shared-utils/ # Utilitaires communs│ │ ├── src/│ │ │ └── index.js│ │ └── package.json│ ├── api-gateway/ # Passerelle API│ │ ├── src/│ │ │ └── server.js│ │ └── package.json│ └── web-app/ # Application web (React/Vue)│ ├── src/│ │ └── App.js│ └── package.json├── tools/ # Scripts et configurations