Monorepo avec TypeScript : organisation du code en pratique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Monorepo avec TypeScript : organisation du code en pratique

\n\n

Dans le développement web moderne, en particulier lorsqu'on travaille avec TypeScript, les développeurs sont souvent confrontés à un dilemme : stocker tout le code dans un seul dépôt (monorepo) ou le diviser en plusieurs petits dépôts (polyrepo). Pour les projets de taille moyenne et grande, où la réutilisabilité du code et une configuration unifiée sont importantes, le monorepo devient un standard de facto. Dans cet article, nous allons voir comment organiser correctement un monorepo en TypeScript, de la structure de base aux techniques avancées.

\n\n

Qu'est-ce qu'un monorepo et pourquoi en a-t-on besoin ?

\n\n

Un monorepo est une approche où le code de plusieurs projets (packages, bibliothèques, applications) est stocké dans un seul dépôt. Dans le contexte de TypeScript, c'est particulièrement pratique car cela permet :

\n\n
    \n
  • Réutiliser les types et les interfaces entre différentes parties du système sans publication sur npm.
  • \n
  • Simplifier le refactoring : une modification dans un package est automatiquement validée dans tous les packages dépendants.
  • \n
  • Avoir une configuration unifiée pour le linter, le formateur et le builder.
  • \n
  • Simplifier le CI/CD : un dépôt, un pipeline.
  • \n
\n\n

Parmi les outils populaires pour travailler avec les monorepos en TypeScript, on distingue Nx, Turborepo et npm/yarn/pnpm workspaces. Nous allons aborder l'approche utilisant pnpm workspaces et TypeScript Project References, car c'est un ensemble minimal et flexible.

\n\n

Structure du monorepo : configuration de base

\n\n

Créons une structure typique de monorepo pour un projet TypeScript. Supposons que nous ayons trois packages : core (types et utilitaires communs), server (backend) et web (frontend).

\n\n

1. Configuration racine

\n\n

Commençons par la racine du projet. Créons un fichier package.json avec workspace :

\n\n
{\n  "name": "my-monorepo",\n  "private": true,\n  "workspaces": [\n    "packages/*"\n  ],\n  "scripts": {\n    "build": "tsc -b",\n    "clean": "tsc -b --clean",\n    "lint": "eslint packages/*/src"\n  }\n}\n
\n\n

Ensuite, configurons le tsconfig.json racine. Utilisons Project References — c'est une fonctionnalité clé de TypeScript pour les monorepos :

\n\n
{\n  "compilerOptions": {\n    "target": "ES2020",\n    "module": "commonjs",\n    "strict": true,\n    "composite": true,\n    "declaration": true,\n    "declarationMap": true,\n    "sourceMap": true,\n    "outDir": "./dist",\n    "rootDir": ".",\n    "skipLibCheck": true\n  },\n  "references": [\n    { "path": "./packages/core" },\n    { "path": "./packages/server" },\n    { "path": "./packages/web" }\n  ]\n}\n
\n\n

Important : l'option composite: true est obligatoire pour les packages référencés par d'autres packages. Elle active la compilation incrémentale et la génération de fichiers .d.ts.

\n\n

2. Configuration du package core

\n\n

Allons dans packages/core. Créons un package.json :

\n\n
{\n  "name": "@my/core",\n  "version": "1.0.0",\n  "main": "dist/index.js",\n  "types": "dist/index.d.ts",\n  "scripts": {\n    "build": "tsc -b"\n  }\n}\n
\n\n

Et le tsconfig.json pour ce package :

\n\n
{\n  "extends": "../../tsconfig.json",\n  "compilerOptions": {\n    "outDir": "./dist",\n    "rootDir": "./src"\n  },\n  "include": ["src"]\n}\n
\n\n

Créons un module simple src/index.ts :

\n\n
export interface User {\n  id: string;\n  name: string;\n  email: string;\n}\n\nexport function greet(user: User): string {\n  return `Hello, ${user.name}!`;\n}\n
\n\n

Maintenant, le package

Blogs

Book Recommendations