fr

Bibliothèques de composants partagées : les stratégies qui existent quand on a 300 projets

Guide complet et sourcé des approches de partage de composants UI entre projets : paquets npm, monorepo, registre shadcn, Module Federation, Bit, Web Components, avec focus sur la propagation des correctifs et la gestion des évolutions à l'échelle.

Cet article fait suite à shadcn/ui : la bibliothèque de composants qui n’en est pas une. L’article précédent détaillait le modèle de distribution de code de shadcn ; celui-ci élargit la perspective à toutes les stratégies de partage de composants entre projets.

Tu as un design system. Des composants métier — réservation, recherche, formulaires. Des briques UI de base — boutons, modales, tableaux. Et tu as 300 projets qui implémentent chacun leur version de ces composants. La tentation est forte de mutualiser. La question est : comment ?

Il n’existe pas de réponse unique. Chaque approche fait un compromis différent entre contrôle (le consommateur décide quand et quoi mettre à jour) et cohérence (tous les projets reflètent la même version). Ce curseur détermine tout le reste : la facilité de propagation des correctifs, le risque d’introduire des régressions, et le coût de maintenance à l’échelle.

Cet article passe en revue six stratégies concrètes, avec pour chacune les mécanismes de propagation, les limites à l’échelle, et les spécificités React (composants clients) vs Astro (composants serveurs).


1. Le spectre contrôle-cohérence

Avant de comparer les outils, il faut comprendre l’axe fondamental qui les différencie :

Contrôle maximal                                    Cohérence maximale
du consommateur                                     de l'écosystème
      │                                                     │
      ▼                                                     ▼
┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐
│ Code     │  │ Git      │  │ Paquets  │  │ Monorepo │  │ Module   │
│ copié    │  │ submodule│  │ npm      │  │ interne  │  │ Federat. │
│ (shadcn) │  │          │  │          │  │          │  │ / CDN    │
└──────────┘  └──────────┘  └──────────┘  └──────────┘  └──────────┘

À gauche, le consommateur possède le code et décide de tout. À droite, le producteur déploie et tous les consommateurs reçoivent la mise à jour instantanément.

Chaque cran vers la droite améliore la propagation des correctifs mais augmente le risque de casser 300 projets d’un coup.


2. Paquets npm sur registre privé

Le principe

Les composants sont compilés, empaquetés et publiés comme des paquets npm classiques (typiquement sous un scope @org/button, @org/dialog). Les consommateurs les installent via npm install et les importent comme n’importe quelle dépendance.

Registres disponibles

RegistreTypeParticularité
npm (npmjs.com)SaaSRéférence. Trusted publishing via OIDC depuis CI
GitHub PackagesSaaSIntégré à GitHub Actions, auth via GITHUB_TOKEN
VerdaccioSelf-hostedOpen source, léger, proxy npm configurable
JFrog ArtifactoryEnterpriseMulti-format, RBAC, politiques de sécurité

Source : npm Docs, Verdaccio, GitHub Packages

Versionnage

Le standard est semver (MAJOR.MINOR.PATCH). L’outil Changesets est devenu la référence pour automatiser le workflow de publication en monorepo :

  1. Les contributeurs déclarent l’impact de leurs changements (major/minor/patch) via des fichiers changeset
  2. La CI agrège les changesets en bumps de version et génère un CHANGELOG.md
  3. Une GitHub Action crée des “versioning PRs” qui regroupent tous les changesets en attente
  4. Le publish supporte le trusted publishing OIDC (pas de tokens stockés)

Source : Changesets — GitHub

Propagation des correctifs

Les consommateurs doivent explicitement mettre à jour leur dépendance. À l’échelle de 300 projets, les organisations utilisent :

  • Renovate Bot ou Dependabot pour créer automatiquement des PR de mise à jour dans chaque projet consommateur
  • Les ranges semver (^1.2.3) pour recevoir automatiquement les patchs et mineurs
  • Des codemods (via jscodeshift ou codemod.com) pour automatiser les migrations d’API lors des changements majeurs

Source : Automating code changes for 100+ repositories — GitNation

Évolutions et risques

Un bump majeur crée une longue traîne de migration : sur 300 consommateurs, certains resteront sur l’ancienne version pendant des mois, voire indéfiniment. C’est à la fois un avantage (pas de casse immédiate) et un problème (fragmentation).

React vs Astro

Les composants React se distribuent via npm sans problème — c’est du JS/TS standard. Les composants Astro (fichiers .astro) sont plus problématiques : ce sont des templates serveur qui dépendent du compilateur Astro, pas des modules JS standards. Astro recommande de distribuer des intégrations ou d’utiliser des composants de framework (React, Vue, Svelte) comme îlots, qui eux fonctionnent parfaitement en paquets npm.

Source : Astro Islands Architecture

À l’échelle

C’est l’approche la plus éprouvée. Atlassian publie chaque composant d’Atlaskit comme un paquet @atlaskit/* indépendant sur npm, consommé par des centaines de projets internes et externes.

Source : Atlaskit — Atlassian Frontend

En pratique, c’est le choix par défaut pour distribuer des composants à des consommateurs que l’on ne contrôle pas. Le modèle est compris de tous, les outils sont matures, et le versionnage sémantique donne un contrat explicite.


3. Monorepo avec paquets internes

Le principe

Le code des composants partagés vit dans un répertoire packages/ aux côtés des applications consommatrices dans un même dépôt. Les gestionnaires de paquets (pnpm, yarn, npm) fournissent le linking via les workspaces.

Deux patterns

Turborepo distingue deux types de paquets :

  • Paquets internes : le code source est consommé directement sans compilation préalable. Référencé via le protocole workspace:*. Le bundler de l’application consommatrice compile le paquet. Zéro configuration de build nécessaire.
  • Paquets publiables : le code est compilé avant publication sur npm. Nécessaire quand les consommateurs sont hors du monorepo.

Source : Turborepo — Internal Packages

Nx a des concepts analogues :

  • Buildable libraries : pré-compilées pour les performances de build incrémental
  • Publishable libraries : générées avec --publishable --importPath=@myorg/lib, produisent des bundles prêts pour npm

Source : Nx — Publishable and Buildable Libraries

Propagation des correctifs

C’est le point fort du monorepo : au sein du dépôt, tous les consommateurs voient le code source à HEAD. Pas de bump de version, pas de publication. Un commit qui corrige un composant est immédiatement visible par toutes les applications.

Pour les consommateurs hors du monorepo, on retombe sur le workflow npm (section précédente).

Évolutions et risques

Au sein du monorepo, l’auteur d’un changement cassant est responsable de mettre à jour tous les consommateurs dans le même commit (changements atomiques). TypeScript détecte les erreurs de compilation immédiatement. La commande affected de Nx identifie les projets impactés.

C’est puissant, mais ça suppose que tous les consommateurs sont dans le même dépôt — ce qui est rarement le cas pour 300 projets.

React vs Astro

Les paquets internes fonctionnent bien pour les deux. Astro peut importer des composants React comme îlots. Les composants .astro peuvent être partagés comme paquets internes si tous les consommateurs utilisent Astro — le build Astro du consommateur gère la compilation. C’est l’une des rares approches où le partage de composants serveur .astro est simple.

Limites à l’échelle

On ne peut pas avoir 300 projets indépendants dans un seul monorepo sauf si tous sont possédés par la même organisation et les équipes acceptent le trunk-based development. Google le fait (2 milliards de lignes de code, 40 000 commits/jour) avec de l’outillage sur mesure (Piper, CitC, Rosie). Avec Turborepo ou Nx, les limites pratiques sont plus basses.

Source : Why Google Stores Billions of Lines of Code in a Single Repository — ACM

En pratique, le monorepo est idéal pour l’équipe qui produit la bibliothèque — développement, tests, CI intégrés. Mais la distribution aux 300 projets consommateurs passe quand même par npm.


4. Distribution de code source (modèle shadcn)

Le principe

Au lieu d’installer une dépendance, un CLI copie le code source des composants directement dans le projet consommateur. Le consommateur possède le code et peut le modifier librement. Ce modèle a été popularisé par shadcn/ui.

Pour les détails du fonctionnement interne — registre JSON, CLI, système de diff — voir l’article dédié à shadcn/ui.

Registre privé d’organisation

Le mécanisme de registre de shadcn est extensible. Une organisation peut créer son propre registre :

{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "my-company",
  "homepage": "https://registry.company.com",
  "items": [
    {
      "name": "booking-form",
      "type": "registry:component",
      "title": "Booking Form",
      "description": "Formulaire de réservation standard",
      "dependencies": ["@radix-ui/react-dialog", "date-fns"],
      "files": [
        {
          "path": "registry/booking-form.tsx",
          "type": "registry:component"
        }
      ]
    }
  ]
}

Les consommateurs installent via :

npx shadcn@latest add @mycompany/booking-form

L’authentification est configurable (Bearer token, API key, basic auth) dans le components.json du consommateur.

Source : shadcn Registry — Getting Started

Propagation des correctifs

C’est la faiblesse principale. Les correctifs ne se propagent pas automatiquement. Les options :

  • Re-exécuter npx shadcn add component --overwrite (écrase les modifications locales)
  • Utiliser npx shadcn diff pour voir ce qui a changé et appliquer manuellement
  • Créer des wrappers au-dessus des composants shadcn non modifiés (stratégie proxy) pour pouvoir --overwrite en toute sécurité

Il n’existe pas d’équivalent Dependabot/Renovate pour les composants distribués par registre.

Évolutions et risques

Puisque le consommateur possède le code, il n’y a pas de changement cassant au sens classique. La copie du consommateur est figée au moment de l’installation. C’est à la fois un avantage (aucune casse inattendue) et un inconvénient (aucune amélioration automatique).

Pour 300 projets, la propagation d’un correctif de sécurité ou d’accessibilité nécessite que chacun re-ajoute le composant manuellement — une opération qui ne passe pas à l’échelle.

React vs Astro

Le CLI v4 de shadcn (mars 2026) supporte nativement React et Astro. Le schéma de registre est agnostique du framework — les items spécifient leur type de fichier, et le CLI s’adapte au projet cible.

À l’échelle

La distribution scale à l’infini — c’est du HTTP servant des fichiers JSON. La propagation des mises à jour ne scale pas.

En pratique, ce modèle convient aux composants que les consommateurs vont fortement personnaliser — design system de base, composants UI fondamentaux. Il convient mal aux composants métier qui doivent se comporter de manière uniforme partout.


5. Git submodules et subtree

Le principe

Partager du code via les mécanismes natifs de Git : submodule (pointeur vers un commit d’un autre dépôt) ou subtree (fusion du code externe dans l’arborescence du consommateur).

Source : Git Subtree vs Submodule — Atlassian

Submodule vs Subtree

AspectSubmoduleSubtree
StockagePointeur (SHA) vers un autre repoCode copié dans l’arborescence
CloneNécessite --recurse-submodulesTransparent, code déjà là
CI/CDConfiguration supplémentaire nécessaireFonctionne nativement
Mise à jourgit submodule update --remotegit subtree pull
Contributions upstreamCommit dans le submodule, pushgit subtree push (manuel)
Taille du repoLégère (juste un pointeur)Augmente (copie complète)

Propagation des correctifs

Aucun automatisme. Chaque consommateur doit manuellement mettre à jour le SHA (submodule) ou puller les changements (subtree). Pas de concept de semver, pas de changelog, pas de contrat de compatibilité.

Évolutions et risques

Un git submodule update peut silencieusement introduire des changements cassants. Il n’existe aucun mécanisme d’avertissement ni outil de migration. C’est du “tout ou rien” — on met à jour au dernier commit ou on reste figé.

À l’échelle

Très mal adapté à 300 projets. Chaque consommateur gère indépendamment la relation submodule/subtree. Aucune visibilité centrale sur les versions utilisées. Les développeurs oublient régulièrement de mettre à jour les submodules, provoquant des désynchronisations silencieuses.

En pratique, les submodules sont un héritage des années où npm n’existait pas ou ne gérait pas les paquets privés. Pour le partage de composants frontend en 2026, il n’y a pas de raison de choisir cette approche.


6. Module Federation

Le principe

Module Federation permet à des applications compilées et déployées indépendamment de partager des modules au runtime via le réseau. Une application “remote” expose des composants ; une application “host” les consomme en chargeant des bundles JavaScript depuis l’URL du remote à l’exécution.

Module Federation 2.0, désormais stable (avril 2026), apporte un runtime découplé de Webpack qui fonctionne avec Webpack, Rspack, Vite et Rollup.

Source : Module Federation 2.0 Reaches Stable Release — InfoQ, module-federation.io

Fonctionnement

┌─────────────────────┐         ┌─────────────────────┐
│   App Host           │         │   Remote "UI"       │
│                     │  HTTP   │                     │
│  import { Button }  │◀────────│  expose: {          │
│    from "ui/Button" │ runtime │    "./Button": ...  │
│                     │         │  }                  │
└─────────────────────┘         └─────────────────────┘
       ▲                               │
       │          Déployé               │
       │       indépendamment           │
       └───────────────────────────────┘

Support Vite actuel

  • @module-federation/vite : plugin officiel MF 2.0 pour Vite
  • Rspack (rspack.rs) : support MF natif, compatible Webpack, basé sur Rust — bien plus rapide que Webpack

Source : Module Federation — Vite Plugin, Rspack — Module Federation

Propagation des correctifs

C’est la killer feature de Module Federation. Puisque les modules sont chargés au runtime depuis l’URL du remote, déployer un correctif sur le remote le propage instantanément à tous les consommateurs à leur prochain chargement de page. Aucun rebuild ni redéploiement côté consommateur.

Évolutions et risques

C’est aussi le plus gros danger. Les dépendances partagées doivent être compatibles en version. Si un remote modifie son API, les consommateurs cassent au runtime — pas au build. Les mitigations :

  • URLs de remote versionnées (https://cdn.example.com/ui/v2/remoteEntry.js)
  • Contract testing entre remotes et hosts
  • Types TypeScript dynamiques via le mécanisme de “dynamic type hinting” de MF 2.0
  • Module Federation 3.0 (2026) gère automatiquement la déduplication des dépendances au niveau du navigateur

Source : Solving Micro-Frontend Challenges with Module Federation — LogRocket

React vs Astro

  • React (client) : c’est le cas d’usage principal de MF. Fonctionne parfaitement.
  • Astro (serveur) : MF est fondamentalement un mécanisme runtime côté client (chargement de bundles JS dans le navigateur). Les composants .astro rendus côté serveur ne peuvent pas être partagés via MF. Les îlots React dans Astro pourraient théoriquement consommer des modules fédérés, mais c’est un chemin peu exploré.
  • Server-Side MF (2025) : permet la fédération de React Server Components, où le serveur assemble du contenu rendu côté serveur depuis plusieurs remotes. C’est nouveau et en évolution.

À l’échelle

MF est conçu pour les architectures micro-frontends où les équipes déploient indépendamment. Il scale bien pour la composition runtime mais a une complexité opérationnelle importante :

  • Chaque remote est un service déployé indépendamment (CI/CD, hébergement, monitoring propres)
  • Latence réseau au chargement des modules distants
  • Défaillances en cascade si un remote est indisponible
  • La matrice de versions des dépendances partagées devient complexe

En pratique, MF est adapté aux grandes applications composées de “tranches” indépendantes (micro-frontends), pas à 300 sites web qui partagent un bouton. C’est une solution d’architecture, pas de distribution de bibliothèque.


7. Bit : le composant comme unité première

Le principe

Bit est une plateforme de développement où chaque composant est une unité indépendamment versionnée, compilée, testée et publiable. Contrairement aux outils de monorepo, Bit traite le composant — pas le paquet ni le dépôt — comme l’unité fondamentale.

Source : bit.dev

Concepts clés

  • Workspace : environnement de développement local pour créer des composants
  • Scope : serveur de collaboration distant (bit.cloud ou self-hosted) qui stocke et sert les composants
  • Isolation : chaque composant a son propre graphe de dépendances, build isolé, tests isolés, rendu de documentation
  • Versionnage : semver individuel par composant. Au tag, le composant est compilé, testé, et son graphe de dépendances verrouillé

Ripple CI : la propagation automatique

Le mécanisme distinctif de Bit est Ripple CI :

  1. Vous mettez à jour le composant A
  2. Ripple identifie automatiquement tous les composants et applications qui dépendent de A
  3. Il compile et teste chaque dépendant à travers tout le système
  4. La propagation est automatique — si A est utilisé par B, C et l’application D, tous sont reconstruits et vérifiés
  5. Fonctionne à travers les scopes (frontières organisationnelles)

Source : Bit — Ripple CI

Propagation des correctifs

  • Dans l’écosystème Bit : Ripple CI propage automatiquement les builds aux dépendants. Les consommateurs avec des ranges semver reçoivent les mises à jour comme avec npm.
  • Consommateurs externes : les composants sont publiés sur npm comme effet de bord du tag. Workflow npm standard.

Limites

  • Vendor lock-in : le modèle mental est très différent de npm/git. L’adoption a un coût significatif.
  • La communauté est plus petite que l’écosystème npm/Turborepo/Nx
  • Pas de support Astro natif (React, Angular, Vue, Node uniquement)
  • Pricing de bit.cloud à l’échelle enterprise

8. Web Components et distribution CDN : le modèle Shopify

Il existe une approche qui ne rentre pas exactement dans les catégories précédentes et qui mérite d’être mentionnée : la distribution via Web Components sur CDN.

L’exemple Polaris

Shopify a reconstruit son design system Polaris en 2025 : de React à des Web Components distribués via CDN.

<script src="https://cdn.shopify.com/shopifycloud/polaris.js"></script>

<!-- Utilisation directe dans n'importe quel framework -->
<polaris-button variant="primary">Réserver</polaris-button>

Source : Polaris Goes Stable — Shopify

Pourquoi c’est intéressant

  • Agnostique du framework : fonctionne dans React, Astro, Vue, HTML statique — partout où il y a un navigateur
  • Propagation instantanée : pas de version dans l’URL, toujours la dernière version. Tous les consommateurs reçoivent les correctifs immédiatement.
  • Aucune installation : un tag <script> suffit
  • Unifié : Admin, Checkout, POS, Customer Accounts utilisent les mêmes composants

Pourquoi c’est risqué

  • Zéro contrôle côté consommateur : une régression dans Polaris casse immédiatement toutes les apps
  • Pas de rollback possible pour un consommateur individuel
  • Dépendance réseau : le CDN devient un SPOF

C’est viable quand le producteur et les consommateurs sont dans la même organisation et que le producteur a les moyens d’investir massivement dans les tests et le release management. Pour un écosystème de 300 projets avec des équipes hétérogènes, c’est un pari risqué.


9. Headless : la couche la plus partageable

Le constat

Quand on veut partager des composants, il faut distinguer ce qui est stable de ce qui change fréquemment :

CoucheStabilitéExemples
Comportement (headless)Très stableNavigation clavier, focus, ARIA, état
Design tokensStableCouleurs, espacement, typographie
StylesVariableCSS, Tailwind classes, CSS-in-JS
CompositionTrès variableLayout, arrangement, business logic

Les bibliothèques headless — Radix UI, React Aria (Adobe), Ark UI (Chakra Systems), Base UI (MUI) — ne fournissent que la première couche. Pas de styles, pas d’opinions visuelles, juste le comportement et l’accessibilité.

Source : Radix UI, React Aria, Ark UI

Pourquoi c’est pertinent pour le partage

Pour 300 projets, les primitives headless sont la couche la plus partageable :

  1. Pas de conflits de style — chaque consommateur applique ses propres tokens
  2. API stable — le comportement change moins souvent que le design
  3. Bundle réduit — pas de CSS embarqué
  4. Composabilité — les primitives se composent, les composants stylisés se remplacent

L’architecture recommandée

┌────────────────────────────────────────────┐
│   Couche 3 : Applications (300 projets)    │
│   → composent les pages, appliquent        │
│     les thèmes spécifiques                 │
├────────────────────────────────────────────┤
│   Couche 2 : Design system d'organisation  │
│   → composants stylisés utilisant          │
│     la couche 1 + tokens maison            │
│   → distribués via npm ou registre shadcn  │
├────────────────────────────────────────────┤
│   Couche 1 : Primitives headless           │
│   → Radix UI, React Aria, Ark UI           │
│   → dépendances npm classiques             │
└────────────────────────────────────────────┘

C’est exactement ce que shadcn/ui a démontré : Radix (couche 1) + Tailwind (couche 2) distribué comme code source. Une organisation peut répliquer ce pattern avec ses propres tokens de design.


10. React client vs Astro serveur : deux problèmes différents ?

Composants React (client)

Les composants React sont des modules JavaScript standard. Toutes les stratégies de distribution fonctionnent : npm, monorepo, registre shadcn, Module Federation.

Le composant est compilé par le bundler du consommateur (Vite, Webpack, Rspack). Le contrat est clair : on exporte des fonctions JSX, le consommateur les importe.

Composants Astro (serveur)

Les composants .astro sont des templates rendus côté serveur. Ce ne sont pas des modules JS standards — ils dépendent du compilateur Astro pour être transformés en HTML. Ça change les options :

StratégieComposants ReactComposants .astro
Paquets npmFonctionne nativementLimité — nécessite qu’Astro compile
Monorepo interneFonctionneFonctionne (le build Astro compile)
Registre shadcnSupporté (CLI v4)Supporté (CLI v4)
Module FederationCas d’usage principalNon supporté
Web ComponentsFonctionneFonctionne

Pour les composants .astro, les options réalistes sont :

  1. Monorepo avec paquets internes — le build Astro du consommateur compile les composants directement
  2. Paquet npm avec les composants .astro — fonctionne, mais nécessite que tous les consommateurs utilisent Astro. Le paquet doit exporter les fichiers .astro tels quels (pas de pré-compilation).
  3. Registre shadcn — le CLI v4 gère nativement le scaffolding pour Astro

En pratique, si les 300 projets n’utilisent pas tous Astro, la stratégie la plus flexible est de distribuer les composants métier comme des composants React utilisables en îlots Astro. Les composants purement serveur (layouts, wrappers HTML) restent dans un paquet npm ou monorepo pour les consommateurs Astro.


11. Codemods : automatiser les migrations

Quand un composant partagé change d’API — renommage de prop, modification de la signature, changement de pattern — les codemods permettent de transformer automatiquement le code des consommateurs.

Comment ça fonctionne

Un codemod est un script qui parse l’AST (Abstract Syntax Tree) du code, identifie les patterns à modifier, et applique la transformation.

# Exemple avec jscodeshift
npx jscodeshift -t transforms/rename-variant-prop.ts src/**/*.tsx
// transforms/rename-variant-prop.ts
// Renomme <Button type="primary"> en <Button variant="primary">
export default function transformer(file, api) {
  const j = api.jscodeshift;
  return j(file.source)
    .findJSXElements("Button")
    .find(j.JSXAttribute, { name: { name: "type" } })
    .forEach((path) => {
      path.node.name.name = "variant";
    })
    .toSource();
}

Source : Codemods for API Refactoring — Martin Fowler

À l’échelle

La plateforme codemod.com permet de créer, publier et exécuter des codemods. Combiné avec Renovate Bot, le workflow devient :

  1. La bibliothèque publie une version majeure avec un codemod associé
  2. Renovate crée une PR de mise à jour dans chaque consommateur
  3. La CI du consommateur exécute le codemod dans la PR
  4. L’équipe du consommateur review et merge

C’est le mécanisme qui rend la propagation des changements cassants faisable à 300 projets. Sans codemods, chaque changement d’API est un blocage.


12. Comparaison synthétique

CritèrenpmMonorepo interneRegistre shadcnGit submoduleModule FederationBit
Propagation des correctifsConsommateur pull (Renovate)Instant (même repo)Manuel (re-add)Manuel (update SHA)Instant (runtime)Ripple CI auto
Risque de casseContrôlé (semver)Nul (atomique)Nul (code possédé)Non contrôléRuntime (dangereux)Contrôlé (Ripple vérifie)
300 consommateursÉprouvéSeulement dans le monorepoDistribution OK, mises à jour nonTrès mal adaptéConçu pour (coût opérationnel)Conçu pour (vendor lock-in)
Composants ReactNatifNatifNatifN/ACas principalNatif
Composants .astroLimitéBonSupporté (CLI v4)N/ANon supportéNon supporté
Maturité outillageTrès hauteHauteEn croissance rapideStable mais manuelMF 2.0 stable (2026)Moyenne
Autonomie du consommateurMoyenne (pin versions)Faible (tout à HEAD)TotaleMoyenneFaible (couplage runtime)Moyenne

13. Recommandation : quelle stratégie pour quel cas

Il n’y a pas de solution universelle. Le choix dépend du type de composant et de la relation avec les consommateurs.

Composants headless / primitives d’accessibilité

Ne pas réinventer. Utiliser Radix UI, React Aria ou Ark UI directement. Ce sont des dépendances npm classiques, très stables, massivement testées. Les 300 projets les importent via npm.

Design system (boutons, modales, champs, typographie)

Registre shadcn privé + paquets npm en complément. Le registre shadcn est idéal pour la distribution initiale — les consommateurs récupèrent un point de départ solide qu’ils peuvent personnaliser. Pour les correctifs critiques (accessibilité, sécurité), un paquet npm avec versionnage sémantique et Renovate Bot assure la propagation.

Le pattern : les composants non modifiés restent en dépendance npm (mises à jour automatiques). Les composants personnalisés sont distribués via registre shadcn (mises à jour manuelles via diff).

Composants métier (formulaire de réservation, module de recherche)

Paquets npm avec Changesets + codemods. Ces composants doivent se comporter de manière uniforme à travers les 300 projets. La distribution via npm avec Renovate Bot pour les mises à jour automatiques et des codemods pour les migrations d’API est l’approche la plus fiable.

Micro-frontends (sections complètes d’application)

Module Federation si les consommateurs sont des applications web qui composent des fragments au runtime. Pertinent pour un portail composant des modules de différentes équipes, pas pour 300 projets indépendants.

L’organisation qui produit la bibliothèque

Monorepo (Turborepo ou Nx) pour le développement interne, avec publication npm pour la distribution externe. C’est le modèle d’Atlassian (Atlaskit) et de la plupart des design systems d’entreprise.


14. Pièges et limitations connus

Le “dependency hell” des composants partagés

Quand un composant partagé a lui-même des dépendances (React, date-fns, zod…), les conflits de version entre la bibliothèque et le consommateur sont inévitables. Solutions :

  • Déclarer les dépendances en peerDependencies (le consommateur fournit sa propre version)
  • Minimiser les dépendances transitives
  • Tester contre plusieurs versions des peer dependencies en CI

La longue traîne de migration

Sur 300 projets, une migration majeure prendra des mois. Certains projets resteront sur l’ancienne version indéfiniment. Il faut planifier :

  • Combien de temps la version N-1 reste maintenue
  • Un mécanisme de deprecation visible (warnings en console, README)
  • Des codemods pour réduire le coût de migration

L’illusion du “on va tout mettre en commun”

Le risque le plus fréquent n’est pas technique mais organisationnel. Mutualiser un composant signifie qu’une équipe en est responsable : maintenance, support, documentation, rétrocompatibilité. Sans cette responsabilité claire, le composant partagé finit abandonné ou forké dans chaque projet — ce qui est pire que de ne pas avoir mutualisé du tout.

Composants .astro : le piège de la pré-compilation

Un paquet npm contenant des fichiers .astro ne peut pas être pré-compilé — les fichiers .astro doivent être compilés par le build du consommateur. Ça signifie que le paquet doit exporter les fichiers source tels quels, ce qui crée un couplage fort avec la version d’Astro du consommateur.


15. Conclusion

Le partage de composants entre 300 projets n’est pas un problème d’outillage — c’est un problème de stratégie de propagation. L’outil ne fait que matérialiser le compromis choisi entre contrôle et cohérence.

En résumé :

  • npm + Renovate + codemods est le socle éprouvé pour distribuer à grande échelle avec un contrat de compatibilité clair
  • Le monorepo est optimal pour l’équipe qui produit la bibliothèque, pas pour les consommateurs
  • Le modèle shadcn (distribution de code source) est puissant pour les composants personnalisables, mais la propagation des mises à jour ne scale pas
  • Module Federation résout un problème différent — la composition runtime d’applications, pas la distribution de bibliothèques
  • Les primitives headless sont la couche la plus partageable parce que c’est celle qui change le moins
  • Chaque composant partagé nécessite un propriétaire, sinon la mutualisation est pire que la duplication

Le choix le plus fréquent en 2026 pour les organisations : un monorepo avec Turborepo ou Nx pour le développement, publication npm avec Changesets pour la distribution, Renovate Bot pour la propagation automatique des mises à jour mineures, et des codemods pour les migrations majeures. Les composants fondamentaux (design system) reposent sur des primitives headless (Radix, React Aria). Les composants hautement personnalisables sont distribués via un registre shadcn privé.

C’est moins séduisant qu’une solution unique, mais c’est ce qui fonctionne à l’échelle.