Lorsque vous commencez à penser aux monorepos TypeScript, vos options s’élargissent rapidement. pnpm, bun, Turborepo, Nx, Changesets, Biome. Tous semblent corrects, mais si vous les mettez tous depuis le début, ce sera lourd. En revanche, si vous coupez tout, vous aurez des ennuis plus tard.
La raison pour laquelle ce genre de discussion est difficile à organiser est que nous recherchons uniquement la « solution optimale » sans considérer les prémisses. Il est préférable de séparer la solution générale et facile à comprendre et la solution pratique pour la configuration qui s’offre à vous.
Cette fois, j’organiserai les deux parties suivantes.
- Configuration sécurisée lors de la création d’un nouveau monorepo TypeScript
- Configuration réaliste basée sur les hypothèses spécifiques de
apps/web,apps/wxt,packages/ui,packages/core
Tout d’abord, la conclusion
| Conditions préalables | Première configuration à choisir | Supplément |
|---|---|---|
| Nouveau monorepo générique. À l’avenir, la publication de packages, l’optimisation de CI et l’intégration de Docker seront prises en compte | pnpm workspace + Turborepo + TypeScript Project References + package.json de exports + Changesets | Le plus stable |
Configuration à 4 packages : apps/web, apps/wxt, packages/ui, packages/core. Je n’utilise pas Docker. Ne publiez pas de packages partagés sur npm | pnpm workspace + Biome + TypeScript Project References | Turborepo n’est pas nécessaire à ce stade |
| Bun fournit l’environnement d’exécution, le gestionnaire de packages et les tests | bun workspace est également candidat | Cependant, pnpm est solide en termes de sécurité de fonctionnement |
En bref, pnpm + turbo est fort en théorie générale. Cependant, dans ce cas, workspace only est suffisant.
Usage général, non difficile
Dès 2026, si vous souhaitez commencer sans vous inquiéter profondément, pnpm workspace est la fondation la plus stable. espace de travail est fourni en standard, les références de packages locaux peuvent être rendues explicites avec le protocole workspace: et les packages cibles peuvent être considérablement réduits avec --filter.
Utilisez Références du projet TypeScript pour les limites de type. La documentation officielle de TypeScript indique également clairement que les projets fractionnés peuvent améliorer le temps de construction, la séparation logique et la construction dans l’ordre des dépendances à l’aide de tsc --build. C’est assez efficace en monorepo.
Si vous ajoutez Turborepo en plus de cela, vous aurez un graphique de tâches, un cache, une exécution parallèle et turbo prune en même temps. [Paramètres de tâche de Turborepo] (https://turborepo.dev/docs/crafting-your-repository/configuring-tasks) ne doit être assemblé qu’autour de dependsOn et outputs, et il y a de la place pour la croissance à mesure que le dépôt grandit.
Si vous avez un package à publier, Changesets s’intégrera naturellement également. documentation de l’espace de travail de pnpm suppose également qu’un outil dédié tel que Changesets est utilisé pour la gestion des versions des packages dans un espace de travail.
En d’autres termes, la solution générale non difficile est la suivante.
| Rôle | Recommandation |
|---|---|
| gestion de l’espace de travail | pnpm workspace |
| Limites de types et constructions incrémentielles | TypeScript Project References |
| Exécution des tâches, parallélisation et mise en cache | Turborepo |
| face publique des limites du paquet | exports sur package.json |
| versionnage / journal des modifications | Changesets |
| peluches / format | Biome ou ESLint + Prettier. Il est plus facile de commencer avec Biome maintenant |
Pourquoi Turborepo n’est-il toujours pas nécessaire dans ce principe ?
La configuration cette fois est assez simple.
packages/corepackages/ui -> packages/coreapps/web -> packages/ui, packages/coreapps/wxt -> packages/ui, packages/coreSi les dépendances sont à ce niveau, exécuter le filtre sur pnpm workspace et tsc -b est suffisant pour le fonctionnement.
Par exemple, la valeur d’inclure Turborepo augmente tout d’un coup dans des situations comme celle-ci.
| Douleur | Pourquoi Turborepo fonctionne |
|---|---|
| Le temps total de construction/test/lint est long | La mise en cache et l’exécution parallèle sont efficaces |
| Je souhaite clarifier l’ordre de dépendance des tâches | dependsOn peut exprimer un graphique |
| Je veux accélérer CI | Le cache distant fonctionne |
| Je souhaite extraire uniquement les packages nécessaires pour Docker | turbo prune peut être utilisé |
D’un autre côté, si vous l’installez à un stade où vous n’êtes pas encore confronté à de tels problèmes, il est difficile de voir l’intérêt au-delà de l’ajout d’un fichier de configuration supplémentaire. Si vous désactivez Docker, l’attrait de prune baissera d’un cran. Changesets n’est pas non plus requis si vous ne publiez pas de packages partagés sur npm.
Par conséquent, sur la base de cette prémisse, il est raisonnable de commencer par pnpm workspace + Biome + TypeScript Project References.
Comment couper des calques
Dans cette division en quatre parties, il est plus important d’éviter toute ambiguïté dans les rôles que dans la sélection des outils.
| Chemin | Choses à mettre | Choses que vous ne devriez pas mettre |
|---|---|---|
packages/core | domaine, schéma, validation, client API, fonction pure, modèle d’état | UI, routage, API du navigateur |
packages/ui | Composant/hook React indépendant de l’environnement | Traitement spécifique à WXT, routeur, stockage d’extension |
apps/web | Assemblage en tant qu’application Web, page, routage, adaptateur | circonstances spécifiques de prolongation |
apps/wxt | script d’arrière-plan/de contenu, API du navigateur, paramètres spécifiques à WXT | Routage spécifique au Web, logique pure pouvant être placée dans la couche partagée |
La dernière chose que je veux éviter est de transformer packages/ui en un lieu pour tout ce qui est partagé. Lorsque des circonstances spécifiques et un routage browser extension commencent à entrer ici, cela devient un point de connexion plutôt qu’une couche partagée. Si cela se produit, les avantages du monorepo diminueront.
## Remarques sur apps/wxt
Vous devriez faire un peu attention à apps/wxt. [Paramètres WXT TypeScript] (https://wxt.dev/guide/essentials/config/typescript.html) étend généralement .wxt/tsconfig.json à partir du tsconfig.json de la racine. Cependant, monorepo peut ne pas prendre cette forme, auquel cas vous devez inclure .wxt/wxt.d.ts dans votre projet TypeScript.
En d’autres termes, bien que apps/wxt fasse partie du monorepo, il est plus stable de le traiter comme un projet TypeScript indépendant.
N’utilisez pas tsconfig.paths comme principal moyen de références transfrontalières
C’est très important.
[Notes de version de TypeScript 5.7] (https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-7.html) indique clairement que les importations qui dépendent de baseUrl et paths ne peuvent pas être réécrites lors de la sortie de JS. En d’autres termes, une conception qui dépasse les limites du package en utilisant uniquement tsconfig.paths peut réussir la vérification de type, mais est susceptible d’être déformée au stade de l’exécution ou de la publication.
Fondamentalement, vous devriez considérer les références transfrontalières en monorepo dans l’ordre suivant.
- Forfaits séparés
- Connectez les dépendances avec
workspace: - Décidez du côté public avec
exportsdepackage.json - Créez une construction d’ordre de dépendance avec
TypeScript Project References
paths est moins susceptible d’être endommagé s’il est conservé comme auxiliaire dans l’emballage.
Biome correspond bien à cette prémisse
Je pense que la décision de supprimer ESLint et de se concentrer sur Biome est tout à fait naturelle. Le guide des grands projets de Biome organise également le principe de l’utilisation différente de la configuration racine et de la configuration imbriquée pour les grands dépôts tels que le monorepo et l’espace de travail. Dans la v2, une configuration basée sur monorepo est également introduite.
À cette échelle, il serait plus simple d’envoyer le lint/format à Biome et de s’occuper uniquement des limites du projet et de construire du côté TypeScript.
Image de configuration minimale
C’est suffisant pour la configuration initiale.
- Placez
pnpm-workspace.yamlà la racine - Placez
tsconfig.jsonde style solution à la racine etreferencesdans chaque paquet. packages/coreetpackages/uiactiventcomposite- Le package partagé spécifie
exportsdepackage.json - Placez
biome.jsonà la racine - Pour
apps/wxt, vérifiez séparément comment gérer les définitions de type WXT.
À ce stade, vous pouvez vous battre pendant assez longtemps.
Quand ajouter le prochain outil
| Quoi ajouter | Quand ajouter |
|---|---|
Turborepo | Build / test / lint est lourd, une optimisation CI est requise, je souhaite clarifier le graphique des tâches |
Changesets | Je souhaite gérer les versions et publier un package partagé |
Nx | Je voulais une génération automatique, polyglotte et une gestion monorepo plus forte |
Migration vers bun workspace | Je voulais unifier le runtime/le gestionnaire de packages/le test sur Bun |
Avec monorepo, il est préférable d’ajouter uniquement là où la douleur survient, plutôt que de tout ajouter depuis le début.
résumé
Il n’existe pas de solution optimale unique pour le monorepo TypeScript. pnpm workspace + Turborepo + TypeScript Project References est puissant pour les réponses générales non difficiles. Cependant, si Docker et la publication de packages ne sont pas encore trop lourds après avoir été divisés en apps/web, apps/wxt, packages/ui et packages/core, ils seraient plus légers et moins susceptibles de tomber en panne si vous commenciez par pnpm workspace + Biome + TypeScript Project References.
L’important n’est pas d’augmenter le nombre d’outils, mais de garder core et ui minces et d’exprimer honnêtement les références transfrontalières avec workspace: et exports. Si cela ne s’effondre pas, il n’est pas trop tard pour ajouter turbo plus tard.
hsb.horse