logo hsb.horse
← Voltar para o índice do blog

Blog

TypeScript Monorepo Organizando a solução ideal edição 2026

Organizamos as funções do espaço de trabalho pnpm, Turborepo, TypeScript Project References, Biome e WXT e resumimos a solução simples de uso geral e a solução prática com uma estrutura de 4 pacotes.

Publicado:

Quando você começa a pensar em monorepos TypeScript, suas opções se expandem rapidamente. pnpm, bun, Turborepo, Nx, Changesets, Biome. Todas parecem corretas, mas se você colocar todas desde o início, vai ficar pesado. Por outro lado, se você cortar tudo, terá problemas mais tarde.

A razão pela qual este tipo de discussão é difícil de organizar é que apenas procuramos a “solução óptima” sem considerar as premissas. É melhor separar a solução de uso geral e fácil de entender e a solução prática para a configuração que está à sua frente.

Desta vez, organizarei as duas partes a seguir.

  1. Configuração segura ao criar um novo monorepo TypeScript
  2. Configuração realista baseada nas suposições específicas de apps/web, apps/wxt, packages/ui, packages/core

Primeiro, a conclusão

Pré-requisitosPrimeira configuração a escolherSuplemento
Novo monorepo genérico. No futuro, o lançamento de pacotes, a otimização de CI e a integração do Docker serão consideradospnpm workspace + Turborepo + TypeScript Project References + package.json de exports + ChangesetsO mais estável
Configuração de 4 pacotes: apps/web, apps/wxt, packages/ui, packages/core. Eu não uso Docker. Não publique pacotes compartilhados no npmpnpm workspace + Biome + TypeScript Project ReferencesTurborepo não é necessário nesta fase
Bun fornece o ambiente de execução, gerenciador de pacotes e testebun workspace também é candidatoNo entanto, pnpm é forte em termos de operação segura

Resumindo, pnpm + turbo é forte na teoria geral. Porém, neste caso, workspace only é suficiente.

Uso geral não difícil

A partir de 2026, se você quiser começar sem se preocupar profundamente, pnpm workspace é a base mais estável. workspace é fornecido como padrão, referências de pacotes locais podem ser explicitadas com o protocolo workspace: e os pacotes de destino podem ser reduzidos consideravelmente com --filter.

Use Referências de projeto TypeScript para limites de tipo. A documentação oficial do TypeScript também afirma claramente que projetos divididos podem melhorar o tempo de construção, a separação lógica e a construção em ordem de dependência usando tsc --build. Isso é bastante eficaz no monorepo.

Se você adicionar Turborepo além disso, você terá gráfico de tarefas, cache, execução paralela e turbo prune de uma só vez. [Configurações de tarefas do Turborepo] (https://turborepo.dev/docs/crafting-your-repository/configuring-tasks) só precisam ser montadas em torno de dependsOn e outputs, e há espaço para crescimento à medida que o repo cresce.

Se você tiver um pacote para publicar, Changesets também se encaixará naturalmente. documentação do espaço de trabalho do pnpm também assume que uma ferramenta dedicada como Changesets é usada para versionamento de pacotes em um espaço de trabalho.

Em outras palavras, a solução não difícil de uso geral é a seguinte.

FunçãoRecomendação
gestão de espaços de trabalhopnpm workspace
Limites de tipo e construções incrementaisTypeScript Project References
Execução de tarefas, paralelização e armazenamento em cacheTurborepo
face pública do limite do pacoteexports de package.json
versionamento / changelogChangesets
fiapos/formatoBiome ou ESLint + Prettier. É mais fácil começar com Biome agora

Por que Turborepo ainda não é necessário nesta premissa?

A configuração desta vez é bastante simples.

packages/core
packages/ui -> packages/core
apps/web -> packages/ui, packages/core
apps/wxt -> packages/ui, packages/core

Se as dependências estiverem neste nível, executar o filtro em pnpm workspace e tsc -b é suficiente para operação.

Por exemplo, o valor da inclusão de Turborepo aumenta repentinamente em situações como esta.

DorPor que Turborepo funciona
O tempo total de construção/teste/lint é longoO cache e a execução paralela são eficazes
Quero esclarecer a ordem de dependência das tarefasdependsOn pode expressar um gráfico
Quero acelerar o CICache remoto funciona
Quero extrair apenas os pacotes necessários para Dockerturbo prune pode ser usado

Por outro lado, se você instalá-lo em um estágio em que ainda não está com tantos problemas, é difícil ver o valor além de adicionar mais um arquivo de configuração. Se você desligar o Docker, o apelo de prune cairá um pouco. Changesets também não é necessário se você não publicar pacotes compartilhados no npm.

Portanto, com base nesta premissa, é razoável começar com pnpm workspace + Biome + TypeScript Project References.

Como cortar camadas

Nesta divisão em quatro partes, é mais importante evitar ambiguidade nas funções do que na seleção de ferramentas.

CaminhoCoisas para colocarCoisas que você não deveria colocar
packages/coredomínio, esquema, validação, cliente API, função pura, modelo de estadoUI, roteamento, API do navegador
packages/uiComponente/gancho React independente do ambienteProcessamento específico WXT, roteador, armazenamento de extensão
apps/webMontagem como aplicação web, página, roteamento, adaptadorcircunstâncias específicas de extensão
apps/wxtscript de plano de fundo/conteúdo, API do navegador, configurações específicas do WXTRoteamento específico da Web, lógica pura que pode ser colocada na camada compartilhada

A última coisa que quero evitar é transformar packages/ui em um lugar para todas as coisas compartilhadas. Quando circunstâncias específicas e roteamento de browser extension começam a entrar aqui, ele se torna um ponto de conexão em vez de uma camada compartilhada. Se isso acontecer, os benefícios do monorepo diminuirão.

Notas sobre apps/wxt

Você deve ter um pouco de cuidado com apps/wxt. Configurações WXT TypeScript geralmente estende .wxt/tsconfig.json do tsconfig.json do root. No entanto, monorepo pode não assumir esse formato; nesse caso, você precisa incluir .wxt/wxt.d.ts em seu projeto TypeScript.

Em outras palavras, embora apps/wxt faça parte do monorepo, é mais estável tratá-lo como um projeto TypeScript independente.

Não use tsconfig.paths como principal meio de referências internacionais

Isto é muito importante.

Notas de versão do TypeScript 5.7 afirma claramente que as importações que dependem de baseUrl e paths não podem ser reescritas ao gerar JS. Em outras palavras, um design que ultrapassa os limites do pacote usando apenas tsconfig.paths pode passar na verificação de tipo, mas provavelmente será distorcido na fase de execução ou publicação.

Basicamente, você deve considerar as referências transfronteiriças no monorepo na seguinte ordem.

  1. Pacotes separados
  2. Conecte dependências com workspace:
  3. Decida o lado público com exports de package.json
  4. Crie uma construção de pedido de dependência com TypeScript Project References

paths tem menos probabilidade de ser danificado se for mantido como auxiliar dentro da embalagem.

Biome se encaixa bem nesta premissa

Acho que a decisão de remover ESLint e focar em Biome é bastante natural. Guia de grandes projetos do Biome também organiza a premissa de usar a configuração raiz e a configuração aninhada de maneira diferente para grandes repositórios, como monorepo e espaço de trabalho. Na v2, também é introduzida uma configuração baseada em monorepo.

Nessa escala, seria mais simples enviar o lint/formato para Biome e cuidar apenas do limite do projeto e construir no lado TypeScript.

Imagem de configuração mínima

Isso é suficiente para a configuração inicial.

  1. Coloque pnpm-workspace.yaml na raiz
  2. Coloque o estilo de solução tsconfig.json na raiz e references cada pacote
  3. packages/core e packages/ui habilitam composite
  4. Pacote compartilhado especifica exports de package.json
  5. Coloque biome.json na raiz
  6. Para apps/wxt, verifique separadamente como lidar com definições de tipo WXT.

Neste ponto, você pode lutar por bastante tempo.

Quando adicionar a próxima ferramenta

O que adicionarQuando adicionar
TurborepoBuild/test/lint é pesado, otimização de CI é necessária, quero esclarecer o gráfico de tarefas
ChangesetsQuero gerenciar versões e publicar um pacote compartilhado
NxEu queria geração automática, poliglota e gerenciamento monorepo mais forte
Migrando para bun workspaceEu queria unificar o tempo de execução/gerenciador de pacotes/teste para Bun

Com o monorepo, funciona melhor adicionar apenas onde ocorre a dor, em vez de adicionar tudo desde o início.

resumo

Não existe uma solução ideal para o monorepo TypeScript. pnpm workspace + Turborepo + TypeScript Project References é forte para respostas não difíceis de uso geral. No entanto, se o Docker e a publicação de pacotes ainda não forem muito pesados ​​após a divisão em apps/web, apps/wxt, packages/ui e packages/core, seria mais leve e menos provável de quebrar se você começar com pnpm workspace + Biome + TypeScript Project References.

O importante não é aumentar o número de ferramentas, mas manter core e ui escassos e expressar referências transfronteiriças honestamente com workspace: e exports. Se isso não falhar, não será tarde demais para adicionar turbo mais tarde.

Referência