Monorepositório com JavaScript: organização de código na prática
\n\nO desenvolvimento de projetos complexos em JavaScript (Node.js) frequentemente enfrenta o problema de gerenciamento de código. Quando você tem vários pacotes, bibliotecas ou microsserviços, cada um vivendo em seu próprio repositório, isso leva à duplicação de código, dificuldade de sincronização de versões e lentidão no CI/CD. A solução é o monorepositório (monorepo). Neste artigo, vamos analisar como organizar um monorepositório com JavaScript na prática: desde a escolha das ferramentas até a configuração da build e publicação.
\n\nO que é um monorepositório e por que ele é necessário?
\n\nMonorepositório é uma abordagem para gerenciamento de código onde todos os pacotes, bibliotecas e aplicações do projeto são armazenados em um único repositório. Ao contrário dos multirrepositórios (cada pacote em seu próprio repo), o monorepositório oferece:
\n\n- \n
- Histórico único de alterações: fácil rastrear como mudanças em uma parte afetam outra. \n
- Reutilização de código: utilitários e componentes comuns vivem em um só lugar sem necessidade de publicação no npm. \n
- Refatoração simplificada: a alteração da API de um pacote é imediatamente visível em todos os dependentes. \n
- Configurações unificadas de CI/CD: um único arquivo de configuração para todos os pacotes. \n
Para JavaScript (Node.js), o monorepositório é especialmente relevante, pois permite eliminar o "inferno das dependências" e acelerar o desenvolvimento. Vamos considerar a implementação prática.
\n\nFerramentas para monorepositório em JavaScript
\n\nExistem várias ferramentas populares no mercado. Vamos considerar duas principais: npm workspaces (integrado ao npm) e Lerna (funcionalidade estendida).
1. npm workspaces (suporte nativo)
\n\nA partir do npm v7, o gerenciador de pacotes suporta workspaces. Esta é a maneira mais simples de começar. Exemplo de estrutura de projeto:
\n\nmy-monorepo/\n├── packages/\n│ ├── core/\n│ │ ├── package.json\n│ │ └── index.js\n│ ├── utils/\n│ │ ├── package.json\n│ │ └── helpers.js\n│ └── app/\n│ ├── package.json\n│ └── server.js\n├── package.json\n└── lerna.json (opcional)\n\npackage.json raiz:
{\n "name": "my-monorepo",\n "private": true,\n "workspaces": ["packages/*"]\n}\n\nAgora todos os pacotes em packages/* são automaticamente vinculados. Para instalar as dependências, basta executar npm install na raiz. As dependências entre pacotes são especificadas de forma padrão:
// packages/app/package.json\n{\n "name": "@my/app",\n "dependencies": {\n "@my/core": "*",\n "@my/utils": "*"\n }\n}\n\nO npm workspaces cria symlinks na pasta node_modules, portanto, os imports funcionam como com pacotes comuns.
2. Lerna (gerenciamento avançado)
\n\nLerna é uma ferramenta para gerenciar monorepositórios com capacidade de publicação, versionamento e execução de scripts em paralelo. Instalação:
\n\nnpm install --global lerna\n\nInicialização no projeto:
\n\nlerna init\n\nArquivo lerna.json:
{\n "version": "independent",\n "npmClient": "npm",\n "packages": ["packages/*"]\n}\n\nO modo independent permite que cada pacote tenha sua própria versão. Comandos principais:
- \n
lerna bootstrap— instala dependências e vincula pacotes. \n lerna run build— executa o scriptbuildem todos os pacotes. \n lerna publish— publica pacotes alterados no npm. \n
Organização prática do código
\n\nVamos considerar um exemplo de configuração de monorepositório para uma aplicação web com backend em Node.js e utilitários comuns.
\n\nPasso 1: Estrutura básica
\n\nVamos criar três pacotes:
\n\n