logo hsb.horse
← Retour au blog

Blog

TypeScript Monorepo Organiser la solution optimale édition 2026

Nous avons organisé les rôles de l'espace de travail pnpm, Turborepo, TypeScript Project References, Biome et WXT, et avons résumé la solution simple à usage général et la solution pratique avec une structure en 4 packages.

Publié:

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.

  1. Configuration sécurisée lors de la création d’un nouveau monorepo TypeScript
  2. 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éalablesPremière configuration à choisirSupplé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 comptepnpm workspace + Turborepo + TypeScript Project References + package.json de exports + ChangesetsLe 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 npmpnpm workspace + Biome + TypeScript Project ReferencesTurborepo n’est pas nécessaire à ce stade
Bun fournit l’environnement d’exécution, le gestionnaire de packages et les testsbun workspace est également candidatCependant, 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ôleRecommandation
gestion de l’espace de travailpnpm workspace
Limites de types et constructions incrémentiellesTypeScript Project References
Exécution des tâches, parallélisation et mise en cacheTurborepo
face publique des limites du paquetexports sur package.json
versionnage / journal des modificationsChangesets
peluches / formatBiome 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/core
packages/ui -> packages/core
apps/web -> packages/ui, packages/core
apps/wxt -> packages/ui, packages/core

Si 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.

DouleurPourquoi Turborepo fonctionne
Le temps total de construction/test/lint est longLa mise en cache et l’exécution parallèle sont efficaces
Je souhaite clarifier l’ordre de dépendance des tâchesdependsOn peut exprimer un graphique
Je veux accélérer CILe cache distant fonctionne
Je souhaite extraire uniquement les packages nécessaires pour Dockerturbo 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.

CheminChoses à mettreChoses que vous ne devriez pas mettre
packages/coredomaine, schéma, validation, client API, fonction pure, modèle d’étatUI, routage, API du navigateur
packages/uiComposant/hook React indépendant de l’environnementTraitement spécifique à WXT, routeur, stockage d’extension
apps/webAssemblage en tant qu’application Web, page, routage, adaptateurcirconstances spécifiques de prolongation
apps/wxtscript d’arrière-plan/de contenu, API du navigateur, paramètres spécifiques à WXTRoutage 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.

  1. Forfaits séparés
  2. Connectez les dépendances avec workspace:
  3. Décidez du côté public avec exports de package.json
  4. 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.

  1. Placez pnpm-workspace.yaml à la racine
  2. Placez tsconfig.json de style solution à la racine et references dans chaque paquet.
  3. packages/core et packages/ui activent composite
  4. Le package partagé spécifie exports de package.json
  5. Placez biome.json à la racine
  6. 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 ajouterQuand ajouter
TurborepoBuild / test / lint est lourd, une optimisation CI est requise, je souhaite clarifier le graphique des tâches
ChangesetsJe souhaite gérer les versions et publier un package partagé
NxJe voulais une génération automatique, polyglotte et une gestion monorepo plus forte
Migration vers bun workspaceJe 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.

Référence