Aller au contenu
useffect.sh
Planifier 30 min avec un senior
Outillage

Monorepo

Un dépôt avec plusieurs packages liés par les workspaces du gestionnaire de paquets ; à surveiller : Metro, l’autolinking et le hissage des dépendances.

Définition

Un monorepo est un dépôt unique qui héberge plusieurs packages liés entre eux par les workspaces du gestionnaire de paquets (Bun, npm, pnpm ou Yarn) : une ou plusieurs apps React Native, un package de composants partagés, un client d’API, parfois un site web. Pour React Native, il pose trois problèmes spécifiques. Metro doit résoudre des modules situés hors du dossier de l’app ; depuis le SDK 52, Expo configure cela automatiquement via expo/metro-config, et la configuration manuelle (watchFolders, nodeModulesPaths) devient à retirer. L’autolinking doit trouver les modules natifs hissés à la racine ou installés en mode isolé ; Expo a ajouté autolinkingModuleResolution au SDK 54, activé automatiquement en monorepo depuis le SDK 55. Et une seule copie de react et de chaque module natif doit exister, sous peine d’erreurs au runtime ou de builds cassés. Il remplace les packages privés publiés et versionnés à part. Un « Invalid hook call » apparu après l’ajout d’un package partagé en est le symptôme typique.

Dans une vraie app

Le diagnostic commence par npm ls react react-native (ou l’équivalent pnpm/yarn) depuis l’app : deux versions de react dans l’arbre donnent le fameux « Invalid hook call », et deux copies d’un module natif cassent le build iOS ou Android. Un champ resolutions (Yarn) ou overrides (npm, pnpm) force une version unique. Les projets sur pnpm en mode isolé qui multiplient les erreurs natives peuvent passer nodeLinker: hoisted dans pnpm-workspace.yaml, ce que la doc Expo propose comme solution de repli.

Les scripts natifs sont l’autre source de pannes : un Podfile ou un build.gradle qui référence ../node_modules/react-native en chemin relatif ne trouve rien quand le package est hissé. La bonne forme utilise require.resolve depuis Node pour localiser react-native et @react-native-community/cli-platform-ios, ce que les templates Expo récents font déjà. Un metro.config.js copié d’un tutoriel avec watchFolders et disableHierarchicalLookup doit être simplifié, puis npx expo start --clear pour vider le cache.

En CI et sur EAS Build, un monorepo demande d’indiquer le dossier de l’app et de ne pas exclure la racine via .easignore. Ma règle pour les packages partagés : des sources TypeScript consommées directement (champ main vers src/index.ts), sans étape de build intermédiaire, tant que le package n’est pas publié.

Nos offres sur ce sujet

Sources

Les 35 termes du glossaire

Un de ces sujets bloque votre app ?

30 minutes avec un senior pour regarder le problème dans votre code. Gratuit.