Monorepo + Yarn Workspaces
Como configurar um Monorepo utilizando o Yarn Workspaces.
Tutoriais da série sobre Monorepo:
- Introdução
- O que é Monorepo?
- O que é Yarn?
- O que é Yarn Workspaces?
- Como instalar o Yarn?
- Construindo o primeiro Monorepo
- Configurando os scripts
- Instalando dependências
- Conclusão
Introdução
Esse é o primeiro de alguns tutoriais que quero escrever sobre Monorepo utilizando o Yarn Workspaces. Venho utilizando bastante essa estratégia e tenho gostado do resultado.
O objetivo desse tutorial é apresentar os primeiros passos com Monorepo.
O que é Monorepo?
Monorepo é uma estratégia de desenvolvimento de software onde o código de várias aplicações são agrupadas em um mesmo repositório.
Essa técnica não é nova, muito pelo contrário, ela já existe há muitos anos, ela apenas ganhou um nome (como tudo hoje em dia 🤭).
Vantagens
Ambiente de desenvolvimento: facilidade para executar o ambiente de desenvolvimento. Basta clonar um único repositório, instalar as dependências de todas as aplicações com um único comando e executar com outro comando.
Reutilização de código: funcionalidades compartilhadas podem ser facilmente extraídas em uma aplicação separada e reutilizadas em outras aplicações.
Gerenciamento de dependências: em múltiplos repositórios, uma dependência externa será baixada múltiplas vezes. No Monorepo, a dependência externa pode ser otimizada e reutilizada.
Gerenciamento de versões: em múltiplos repositórios, quando uma aplicação é versionada, todas as outras aplicações que dependem dela precisam ser atualizadas. No Monorepo, não há essa necessidade, pois o código está linkado.
Desvantagens
CI/CD: realizar o Continuous Integration ou Continuous Delivery com Monorepo pode ser complicado. Não é fácil identificar qual aplicação foi alterada para iniciar os processos de CI/CD apenas para ela.
Segurança: como todas as aplicações estão no mesmo repositório, os desenvolvedores têm acesso a tudo. Isso pode causar alguns problemas de segurança. Obs.: há aplicações em que esse cenário não é considerado uma desvantagem.
Equívocos: com muitas aplicações em um mesmo repositório, se não prestar atenção no diretório que está aberto no Terminal, você acaba executando ou instalando alguma dependência na aplicação errada.
O que é Yarn?
Yarn é uma alternativa ao npm, é um gerenciador de dependências do Node. Ele foi criado para tentar resolver alguns problemas do npm.
Para mais informações sobre o Yarn: https://yarnpkg.com.
O que é Yarn Workspaces?
Workspaces é uma funcionalidade do Yarn que permite agrupar múltiplas aplicações em um único repositório. Ele é o grande facilitador para a criação de Monorepos. Basta informar quais são os diretórios no arquivo package.json
para que o Yarn seja capaz de instalar as dependências e linkar as aplicações locais.
Para mais informações sobre o Yarn Workspaces: https://yarnpkg.com/en/docs/workspaces.
Como instalar o Yarn?
Acesse a página com as instruções de instalação, escolha o sistema operacional, a versão e siga os passos descritos nessa página. Para verificar se a instalação ocorreu com sucesso, abra o Terminal e digite:
$ yarn --version1.19.1
Se quiser entender mais como o Yarn funciona, acesse a documentação: https://yarnpkg.com/en/docs.
Construindo o primeiro Monorepo
Nesse tutorial, iremos construir um Monorepo com duas aplicações extremamente simples:
sum
: biblioteca que exporta uma funcionalidade para somar dois númeroscalc
: aplicação que utiliza a funcionalidade de soma
Criando o repositório principal
O primeiro passo é criar o diretório principal e inicializar uma nova aplicação Node
. Para isso, abra o Terminal e digite:
$ mkdir monorepo$ cd monorepo$ yarn init -y
Esse comando gera o arquivo package.json
na raíz da aplicação:
{"name": "monorepo","version": "1.0.0","main": "index.js","license": "MIT"}
Como o package.json
principal não vai exportar nenhuma funcionalidade, precisamos fazer 02 alterações:
- Excluir o campo
main
- Adicionar o campo
private
comotrue
, para que o repositório não seja publicado acidentalmente
{"name": "monorepo","version": "1.0.0","license": "MIT","private": true}
Configurando o Workspace
Para configurar o Monorepo é necessário criar o campo workspaces
no arquivo package.json
. Há duas maneiras de configurar o campo workspaces
.
- Criar os diretórios
calc
esum
na raíz do repositório e adicionar o nome das duas aplicações no campoworkspaces
no arquivopackage.json
. O problema dessa maneira é que sempre que formos adicionar ou excluir aplicações do workspace, precisamos lembrar de alterar o arquivopackage.json
.
Estrutura de arquivos e diretórios
.|--- calc|--- sum|--- package.json
Arquivo package.json
{"workspaces": ["sum", "calc"]}
- Criar um diretório
packages
na raíz, criar os diretórioscalc
esum
dentro do diretóriopackages
e adicionar um glob no campoworkspaces
no arquivopackage.json
. Essa é a melhor maneira, pois informamos ao Yarn que todas as aplicações dentro do diretóriopackages
fazem parte do workspace. Com isso não precisamos mais nos preocupar com o campoworkspaces
.
.|--- packages| |--- calc| |--- sum|--- package.json
{"workspaces": {"packages": ["packages/*"]}}
Nesse tutorial iremos utilizar a segunda opção.
Criando a biblioteca
Crie um diretório sum
dentro do diretório packages
, abra o diretório sum
no Terminal e digite yarn init -y
. Esse comando inicializa uma nova aplicação Node
no diretório sum
.
{"name": "sum","version": "1.0.0","main": "index.js","license": "MIT"}
Crie o arquivo index.js
no diretório sum
.
module.exports = (x, y) => {return x + y;};
Criando a aplicação
Crie um diretório calc
dentro do diretório packages
, abra o diretório calc
no Terminal e digite yarn init -y
. Esse comando inicializa uma nova aplicação Node
no diretório calc
.
{"name": "calc","version": "1.0.0","main": "index.js","license": "MIT"}
Para utilizar a biblioteca sum
na aplicação calc
é necessário instalá-la como dependência. Abra o diretório calc
no Terminal e digite:
É necessário utilizar a versão exata do pacote para que o Yarn saiba onde procurar. Se você não informar a versão, o Yarn vai tentar encontrar o pacote no registro do npm (caso ele seja o default).
{"dependencies": {"sum": "1.0.0"}}
Crie o arquivo index.js
no diretório calc
.
const sum = require('sum');const total = sum(5, 5);console.log(total);
Para executar a aplicação e testar se tudo está funcionando, abra o Terminal no diretório calc
e digite:
$ node index.js10
Utilizando scoped packages
Podemos utilizar scoped packages também.
- Altere o nome do pacote da aplicação
calc
{"name": "@monorepo/calc"}
- Altere o nome do pacote da biblioteca
sum
{"name": "@monorepo/sum"}
- Remova e instale novamente a biblioteca
sum
. Abra o diretóriocalc
no Terminal e digite:
$ yarn remove sum
- Altere a referência no arquivo
index.js
da aplicaçãocalc
const sum = require('@monorepo/sum');
Para executar a aplicação e testar se tudo continua funcionando, abra o Terminal no diretório calc
e digite:
$ node index.js10
Analisando o diretório node_modules
O Yarn Workspaces já faz o trabalho de linkagem das aplicações automaticamente para nós. Dê uma olhada no diretório node_modules.
$ l node_modules@monorepo$ l node_modules/@monorepocalc -> ../../packages/calcsum -> ../../packages/sum
Dependências externas
O processo para instalar dependências externas é o mesmo. Abra o diretório sum
no Terminal e digite:
$ yarn add chalk
Altere o arquivo index.js
da aplicação sum
.
const chalk = require('chalk');module.exports = (x, y) => {console.log(`Adding ${chalk.blue(x)} + ${chalk.blue(y)}`);return x + y;};
Abra o diretório calc
no Terminal e digite:
$ yarn add chalk
Altere o arquivo index.js
da aplicação calc
.
const chalk = require('chalk');const sum = require('@monorepo/sum');const total = sum(5, 5);console.log(chalk.green(total));
Para executar a aplicação e testar se tudo continua funcionando, abra o Terminal no diretório calc
e digite:
$ node index.jsAdding 5 + 510
Configurando os scripts
Para configurar os scripts é muito simples.
Configurando o script da aplicação calc
Edite o arquivo package.json
da aplicação calc
e adicione o script start
.
{"scripts": {"start": "node index.js"}}
Abra o Terminal no diretório calc
e digite:
$ yarn start
Output
yarn run v1.19.1$ node index.jsAdding 5 + 510✨ Done in 0.20s.
Configurando o script do Monorepo
Edite o arquivo package.json
do diretório raíz e adicione o script start
.
{"scripts": {"start": "yarn workspace @monorepo/calc start"}}
Abra o Terminal no diretório raíz e digite:
$ yarn start
Output
yarn run v1.19.1$ yarn workspace @monorepo/calc start$ node index.jsAdding 5 + 510✨ Done in 1.13s.
Instalando dependências
Nessa seção vamos entender como funciona o processo de instalação de dependências com o Yarn Workspaces. Essa é uma das grandes vantagens de trabalhar com Monorepo.
Primeiro vamos apagar a pasta node_modules
para simular que acabamos de clonar o repositório. Abra o Terminal no diretório raíz e digite:
$ rm -rf node_modules
No mesmo diretório, digite:
$ yarn
Com apenas um comando, todas as dependências de todas as aplicações foram instaladas.
MAGIC! 😘
Conclusão
Esse tutorial foi bem introdutório mas acho que deu para perceber a facilidade de trabalhar com Monorepos e Yarn Workspaces. Pretendo continuar escrevendo sobre esse assunto ao longo das próximas semanas.
Caso queira dar uma olhada no código final desse tutorial e acompanhar a sequência de commits: https://github.com/robertoachar/monorepo.
Gostaria de agradecer ao Sibelius Seraphini pela revisão. Obrigado! 😉
Próximos passos
- Leia o artigo sobre a introdução ao Yarn Workspaces.
- Leia a documentação do Yarn Workspaces
- Estude as funcionalidades
yarn workspaces
eyarn workspace