
Nos últimos anos, o conceito de
mono-repositórios se estabeleceu com sucesso, pois pode simplificar significativamente o processo de desenvolvimento de projetos de software modulares, como infraestruturas baseadas em microsserviços. As principais vantagens dessa abordagem arquitetônica são óbvias na prática; portanto, proponho criar seu próprio
repositório de teste
a partir do zero, entendendo simultaneamente as nuances de trabalhar com
áreas de trabalho de fios e
lerna . Bem, vamos começar!
Considere a estrutura do nosso projeto, que será três bibliotecas localizadas na pasta
packages / , bem como
package.json no diretório raiz.
├── package.json └── packages ├── app │ ├── index.js │ └── package.json ├── first │ ├── index.js │ └── package.json └── second ├── index.js └── package.json
Entende-se que temos duas bibliotecas independentes
primeiro e
segundo , além de uma biblioteca de
aplicativos que importará funções das duas primeiras. Por conveniência, todos os três pacotes são colocados no diretório
packages . Você pode deixá-los na pasta raiz ou colocá-los em um diretório com qualquer outro nome, mas, para seguir as convenções geralmente aceitas, as colocaremos dessa maneira.
As bibliotecas
primeiro e
segundo por simplicidade do experimento conterão apenas uma função no
index.js , cada uma das quais retornará uma sequência de hello em nome do módulo. Para o
primeiro exemplo, ficará assim:
No módulo do
aplicativo , exibiremos a mensagem
Oi do aplicativo no console, além de cumprimentos de dois outros pacotes:
Para que o
primeiro e o
segundo estejam disponíveis no
aplicativo , os denotamos como dependências nas
dependências .
Além disso, para cada biblioteca, adicionamos o prefixo
@ monorepo / no
nome do valor na frente do nome principal do pacote ao
package.json local.
Por que preciso de um prefixo com um ícone de cachorro na frente do nome do pacote npm (@ monorepo /)?A adição de um prefixo é opcional, mas esse
é exatamente o
tipo de convenção de nomenclatura
de pacotes a que muitos monorepositórios aderem:
babel ,
interface do usuário material ,
angular e outros. O fato é que cada usuário ou organização tem seu próprio
escopo no site
npm , portanto, há uma garantia de que todos os módulos com o
@ somescope / postfix são criados pela equipe do
somescope e não pelos atacantes. Além disso, torna-se possível chamar nomes de módulos que já foram utilizados. Por exemplo, você não pode simplesmente criar e criar seu próprio módulo de
utilitários , porque essa biblioteca
já existe . No entanto, adicionando o postfix
@ myscopename / , podemos obter nossos utils (
@ myscopename / utils ) com blackjack e jovens senhoras.
Um análogo da vida real para o nosso projeto de teste pode ser várias bibliotecas para trabalhar com dados, ferramentas de validação, análise ou apenas um conjunto de componentes da interface do usuário. Se assumirmos que vamos desenvolver um aplicativo
Web e
móvel (por exemplo, usando
React e
React Native, respectivamente), e tivermos parte da lógica reutilizada, pode valer a pena colocá-lo em componentes separados, para uso posterior em outros projetos. Adicione a isso o servidor no
Node.js e você terá um caso muito real da vida.
Áreas de trabalho de fios
O toque final antes de criar um
repositório mono completo será o design do
package.json na raiz do nosso repositório. Preste atenção à propriedade de
áreas de trabalho - especificamos o valor de
packages / * , que significa "todas as subchaves na pasta
packages ". No nosso caso, este é um
aplicativo ,
primeiro ,
segundo .
Além disso,
“private”: true deve ser especificado em
package.json , pois os
espaços de trabalho estão disponíveis apenas em projetos privados.
Para que tudo decole, execute o comando
yarn (análogo ao
yarn install ou
npm install ) no diretório raiz. Como as dependências existentes no módulo de
aplicativo são definidas como
áreas de trabalho no
pacote raiz.json , na verdade, não faremos download de nada do
npm-registry , mas simplesmente vincularemos ("vincularemos") nossos pacotes.
yarn

Agora podemos executar o comando do
nó. no diretório raiz que executará o script no
arquivo packages / app / index.js .
node .

Vamos ver como isso funciona.
Ao chamar
yarn , criamos links simbólicos em
node_modules para nossos diretórios na pasta
packages .

Devido a esse relacionamento nas dependências, tivemos uma grande vantagem - agora, ao mudar no
primeiro e no
segundo módulos, nosso
aplicativo receberá a versão atual desses pacotes sem reconstruir. Na prática, é muito conveniente, porque podemos conduzir o desenvolvimento local de pacotes, ainda os definindo como dependências de terceiros (que acabam se tornando).
A próxima vantagem importante que você pode obter ao trabalhar com
áreas de trabalho de fios é a organização do armazenamento de dependências de terceiros.
Saiba mais sobre o armazenamento de dependências no nível superior.Suponha que
desejássemos usar a biblioteca
lodash no
primeiro e no
segundo .
Ao executar o comando yarn add lodash a partir dos diretórios apropriados, receberemos uma atualização para o
package.json local - a versão atual do pacote aparecerá em
dependências .
"dependencies": { "lodash": "^4.17.11" }
Quanto ao
próprio pacote
lodash - fisicamente, a biblioteca será instalada no
node_modules no nível raiz uma vez.
Se a versão exigida do pacote externo (no nosso caso,
lodash ) for diferente para o
primeiro e o segundo (por exemplo,
primeiro você precisará do
lodash v3.0.0 e no
segundo v4.0.0 ), um pacote com uma versão inferior (
3.0.0 ) chegará ao
nó node_modules raiz , e a versão
lodash para o
segundo módulo será armazenada em
pacotes locais
/ second / node_modules .
Além das vantagens, essa abordagem pode ter pequenas desvantagens, que o
fio permite ignorar com a ajuda de sinalizadores adicionais. Você pode ler mais sobre essas nuances na
documentação oficial .
Adicionar Lerna
O primeiro passo para trabalhar com o
lerna é instalar o pacote. Geralmente eles executam uma instalação global (
yarn global add lerna ou
npm i -g lerna ), mas se você não tiver certeza se deseja usar esta biblioteca, poderá usar a chamada usando
npx .
Inicializaremos o
lerna a partir do diretório raiz:
lerna init

De fato, realizamos várias ações ao mesmo tempo com a ajuda de um comando: criamos um repositório git (se não tivesse sido inicializado antes disso), criamos um arquivo
lerna.json e atualizamos nosso
pacote raiz.json .
Agora, no recém-criado arquivo
lerna.json, adicione duas linhas -
“npmClient”: “yarn” e
“useWorkspaces”: true . A última linha diz que já usamos
áreas de trabalho de fios e não há necessidade de criar a
pasta app / node_modules com links simbólicos para o
primeiro e o
segundo .
Testes com Lerna
Para mostrar a conveniência de trabalhar com o
lerna, adicione testes para nossas bibliotecas.
No diretório raiz, instalamos o pacote para testing -
jest . Execute o comando:
yarn add -DW jest
Por que preciso do sinalizador -DW?O sinalizador -D (- dev) é necessário para que o pacote jest seja instalado como uma dependência do desenvolvedor, e o sinalizador -W (- ignore-workspace-root-check) permite a instalação no nível raiz (o que precisamos).
O próximo passo é adicionar um arquivo de teste ao nosso pacote. Para a conveniência do nosso exemplo, faremos todos os testes semelhantes. Para o
primeiro exemplo, o arquivo de teste terá a seguinte aparência:
Também precisamos adicionar um script para executar testes no
package.json de cada uma de nossas bibliotecas:
O toque final será atualizar o
pacote root.json . Adicione um script de
teste que chamará
lerna run test --stream . O parâmetro após
lerna run define o comando que será chamado em cada um de nossos pacotes a partir da pasta
packages / , e o sinalizador
--stream nos permitirá ver a saída dos resultados no terminal.
Como resultado, o
package.json do diretório raiz ficará assim:
Agora, para executar os testes, precisamos apenas executar o comando a partir da raiz do nosso projeto:
yarn test

Atualização de versão com Lerna
A próxima tarefa popular, com a qual o
lerna pode lidar com a qualidade, será atualizar as versões dos pacotes. Imagine que, após a implementação dos testes, decidimos atualizar nossas bibliotecas da 1.0.0 para a 2.0.0. Para fazer isso, basta adicionar a linha
“update: version”: “lerna version --no-push” ao campo de
scripts do root
package.json e, em seguida, execute
yarn update: version no diretório raiz. O sinalizador
--no-push é adicionado para que, após a atualização da versão, as alterações não sejam enviadas para o repositório remoto, o que o
lerna faz por padrão (sem esse sinalizador).
Como resultado, nosso root
package.json ficará assim:
Execute o script de atualização da versão:
yarn update:version
Em seguida, seremos solicitados a selecionar a versão para a qual queremos mudar:

Ao clicar em
Enter , obtemos uma lista de pacotes nos quais a versão é atualizada.

Confirmamos a atualização digitando
y e recebemos uma mensagem sobre a atualização bem-sucedida.

Se tentarmos executar o comando
git status , não receberemos a mensagem
para confirmar, trabalhando em uma árvore limpa , porque
A versão lerna não apenas atualiza as versões dos pacotes, mas também cria um commit e uma tag git indicando a nova versão (v2.0.0 no nosso caso).
Recursos de trabalho com a equipe da versão lernaSe você adicionar a linha
"version": "lerna version --no-push" em vez de
"update: version": "lerna version --no-push" no campo de
scripts do root
package.json , é possível que encontre comportamentos inesperados e console vermelho. O fato é que o
npm-scripts chama o comando
version (script reservado) imediatamente após atualizar a versão do pacote, o que leva a uma chamada recursiva para a
versão lerna . Para evitar essa situação, basta atribuir um nome diferente ao script, por exemplo,
update: version , como foi feito em nosso exemplo.
Conclusão
Esses exemplos mostram um centésimo de todas as possibilidades que a
lerna possui em conjunto com os
espaços de trabalho de fios . Infelizmente, até agora não encontrei instruções detalhadas para trabalhar com monorepositórios em russo, para que possamos assumir que o começo foi feito!
Link para o repositório do projeto de teste.