Monorepo com TypeScript: organização de código na prática
O desenvolvimento moderno de frontend e backend enfrenta cada vez mais o problema de gerenciar vários projetos inter-relacionados. Quando o número de pacotes, bibliotecas e aplicações cresce, a abordagem tradicional com repositórios separados (multi-repo) começa a desacelerar o desenvolvimento: duplicação de código, dificuldades com sincronização de versões e longos ciclos de revisão. A solução é o monorepo, especialmente em conjunto com TypeScript. Neste artigo, vamos abordar aspectos práticos da organização de código em um monorepo com TypeScript: desde a escolha de ferramentas até exemplos concretos de estrutura e configuração.
O que é um monorepo e por que ele é necessário para projetos TypeScript?
Monorepo é uma abordagem onde o código de vários projetos (pacotes, bibliotecas, serviços) é armazenado em um único repositório Git. Para TypeScript, isso é especialmente relevante, pois a linguagem de tipagem forte permite reutilizar facilmente tipos e interfaces comuns entre diferentes partes do sistema.
Principais vantagens do monorepo com TypeScript:
- Versão única de dependências — elimina-se a situação onde diferentes projetos usam versões diferentes da mesma biblioteca.
- Reutilização de código — tipos, utilitários e configurações comuns ficam facilmente acessíveis a todos os pacotes.
- Commits atômicos — alterações que afetam vários pacotes podem ser commitadas juntas.
- Simplificação de CI/CD — um único pipeline para build e teste de todas as partes.
No entanto, o monorepo exige disciplina na organização do código. Sem uma estrutura adequada, ele se transforma em um "depósito de lixo". TypeScript ajuda a organizar graças à tipagem forte e ao sistema modular.
Escolha da ferramenta para gerenciar o monorepo
No mercado, existem várias ferramentas populares para trabalhar com monorepos. Vamos considerar as duas mais comuns para TypeScript: Nx e Turborepo.
Nx — um sistema poderoso com suporte a monorepos, geração de código e cache avançado. É ideal para grandes projetos com muitos pacotes.
Turborepo — uma ferramenta mais leve e rápida da Vercel, focada em simplicidade. É perfeita para projetos médios e equipes que desejam configuração mínima.
Exemplo de configuração básica com Turborepo:
// turbo.json{ "$schema": "https://turbo.build/schema.json", "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] }, "test": { "dependsOn": ["build"] }, "lint": {} }}Para TypeScript, é obrigatória a configuração do tsconfig.json com suporte a project references. Isso permite que o compilador entenda as dependências entre os pacotes.
// tsconfig.base.json{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "composite": true, "declaration": true, "declarationMap": true, "sourceMap": true, "outDir": "./dist", "rootDir": "./src" }}Organização prática da estrutura do monorepo
O princípio chave é a divisão do código em camadas lógicas. Vamos considerar uma estrutura típica para um monorepo TypeScript com aplicação web e backend:
monorepo/├── apps/│ ├── web/ # Aplicação Frontend (React, Vue, etc.)│ └── api/ # Serviço Backend (Express, NestJS)├── packages/│ ├── shared/ # Tipos e interfaces comuns│ ├── utils/ # Funções utilitárias│ ├── ui/ # Componentes de UI (se usado)│ └── config/ # Configurações comuns (eslint, tsconfig)├── tools/ # Scripts e ferramentas para CI/CD├── turbo.json├── package.json└── tsconfig.