Espaços de trabalho

Espaços de trabalho (ou workspaces) são uma nova maneira de montar sua arquitetura de pacotes, e estão disponíveis por padrão desde o Yarn 1.0. Eles permitem que você configure vários pacotes de tal forma que basta você executar yarn install uma vez para que a instalação ocorra em todos esses pacotes de uma só vez.

Por que fazer isso?

  • Suas dependências poderão ser vinculadas umas às outras. Dessa forma, seus espaços de trabalho podem depender um do outro, sempre usando o código mais atualizado disponível. Isso faz deles um mecanismo melhor que o yarn link, já que ele afeta apenas as pastas do seu espaço de trabalho, ao invés do seu sistema inteiro.

  • Todas as dependências dos seus projetos serão instaladas juntas, dando ao Yarn maior liberdade para melhor otimizá-las.

  • O Yarn usará apenas um arquivo de travamento (lockfile) ao invés de um arquivo diferente para cada projeto, o que diminui conflitos e facilita revisões.

Como posso usar isso?

Adicione o seguinte conteúdo a um arquivo package.json. De agora em diante, chamaremos essa pasta de “raiz do espaço de trabalho”:

package.json

{
  "private": true,
  "workspaces": ["espaco-a", "espaco-b"]
}

Observe que o private: true é obrigatório! Espaços de trabalho não foram feitos para serem publicados, então adicionamos essa medida de segurança para garantir que nada possa ser acidentalmente exposto.

Após criar esse arquivo, crie duas novas subpastas chamadas espaco-a e espaco-b. Em cada uma delas, crie outro arquivo package.json com o seguinte conteúdo:

espaco-a/package.json:

{
  "name": "espaco-a",
  "version": "1.0.0",

  "dependencies": {
    "cross-env": "5.0.5"
  }
}

espaco-b/package.json:

{
  "name": "espaco-b",
  "version": "1.0.0",

  "dependencies": {
    "cross-env": "5.0.5",
    "espaco-a": "1.0.0"
  }
}

Por fim, execute yarn install em algum lugar, de preferência na raiz do espaço de trabalho. Se tudo der certo, você terá uma hierarquia de arquivos como esta:

/package.json
/yarn.lock

/node_modules
/node_modules/cross-env
/node_modules/espaco-a -> /espaco-a

/espaco-a/package.json
/espaco-b/package.json

E é isso! A importação do espaco-a a partir de um arquivo localizado no espaco-b agora usará o mesmíssimo código que está atualmente dentro do seu projeto - ao invés de usar o que estiver publicado no GitHub, por exemplo. Além disso, o pacote cross-env não está duplicado entre os espaços e foi colocado na raiz do seu projeto, de forma a ser usado por ambos o espaco-a e o espaco-b.

Como isso se compara ao Lerna?

Os espaços de trabalho do Yarn são peças de baixo nível que ferramentas como o Lerna podem usar (e de fato usam!). Eles nunca vão tentar dar suporte às funcionalidades de alto nível que o Lerna oferece, mas, ao implementar a lógica principal de resolução de pacotes e criação de links simbólicos dentro do próprio Yarn, acreditamos permitir novas formas de uso e melhorar o desempenho.

Dicas e macetes

  • O campo workspaces é um array contendo os caminhos para cada espaço de trabalho. Como a tarefa de acompanhar cada uma delas pode se tornar tediosa, este campo também aceita padrões glob! Por exemplo, o Babel referencia todos os seus pacotes através de uma única diretiva, packages/*.

  • Os espaços de trabalho são estáveis o suficiente para serem usados em aplicações de grande porte e não devem mudar nada na maneira que as instalações normalmente funcionam. Mas se você acredita que eles estão fazendo algo deixar de funcionar como deveria, você pode desativá-los adicionando a seguinte linha ao seu arquivo Yarnrc:

      workspaces-experimental false
    

Limitações e ressalvas

  • A disposição dos pacotes será diferente entre seu espaço de trabalho e o que seus usuários receberão (as dependências do espaço de trabalho estarão localizadas um nível acima na hierarquia de pastas). Mas considerando que esse tipo de layout de pastas já era algo perigoso, já que o processo de elevar dependências não é padronizado, então teoricamente isso não é nenhuma novidade.

  • No exemplo acima, se espaco-b dependesse de uma versão diferente daquela que consta no package.json do espaco-a, a dependência seria então instalada a partir do Github, ao invés de um link simbólico local ser criado. A razão disso é que alguns pacotes realmente precisam usar suas versões anteriores para construir as novas (o Babel é um deles).

  • Tome cuidado ao publicar pacotes vindos de um espaço de trabalho. Se você estiver preparando seu próximo lançamento e decidiu usar uma nova dependência, mas se esqueceu de declará-la no arquivo package.json, há a possibilidade dele ainda passar nos seus testes localmente caso outro pacote já a tenha baixado para a raiz do espaço de trabalho. No entanto, ele não irá funcionar para os usuários que o baixarem do registro, já que a lista de dependências estará incompleta, e eles não terão como baixar a nova dependência. Atualmente, não existe uma maneira para lançar uma advertência nessa situação.

  • Os espaços de trabalho precisam estar exatamente um nível abaixo da raiz do espaço de trabalho na hierarquia de pastas. Você não pode e não deve referenciar espaços de trabalho que estiverem fora dessa hierarquia de arquivos.

  • Não há suporte para espaços de trabalho aninhados no momento.