Gerenciamento de Dependências

Este documento define as práticas recomendadas para gerenciar dependências em projetos JavaScript/TypeScript em todo o ecossistema Decentraland. Aplica-se a front-end, back-end, SDKs, bibliotecas compartilhadas e qualquer pacote baseado em npm/yarn/pnpm.

Resumo:

  • Estratégia de versão → Usar versões exatas/fixas para dependencies (segurança) e devDependencies (ambiente de desenvolvimento consistente). Usar intervalos de versão apenas para peerDependencies (flexibilidade).

  • Exceção → Pacotes Decentraland (@dcl/*, decentraland-*) podem usar intervalos de versão (^) pois são pacotes internos confiáveis.

  • Bibliotecas/pacotes compartilhados → Usar peerDependencies com intervalos de versão (^) para bibliotecas compartilhadas (React, @dcl/schemas, etc.). Usar dependencies com versões exatas apenas para utilitários seguros para duplicar.

  • Apps/serviços finais → Usar dependencies com versões exatas para pacotes em tempo de execução (React, ethers, etc.).

1. Justificativa

Muitas bibliotecas dependem de singletons globais, React Context, identidade de classe, caches compartilhados, enums de schema ou pools de BD compartilhados. Instalar múltiplas versões da mesma biblioteca pode causar:

  • Context não compartilhado entre cópias

  • Caches ou pools duplicados

  • Falhas em verificações instanceof

  • Incompatibilidades de enum/símbolo

  • Aumento no tamanho do bundle

  • Bugs em tempo de execução difíceis de diagnosticar

O gerenciamento correto de dependências previne esses problemas.

Não-objetivos

Este padrão não não tenta:

  • Impor um único gerenciador de pacotes (npm, yarn, pnpm são todos suportados)

  • Garantir uma única cópia física em node_modules (o foco é na deduplicação em tempo de execução/bundle)

2. Definições

Campo
Propósito
Responsabilidade do consumidor
Aplica-se a

dependencies

Pacotes usados internamente pelo módulo

Nenhum - o consumidor não é esperado para fornecê-los

Apps e bibliotecas

peerDependencies

Pacotes que devem resolver para uma única versão efetiva em tempo de execução

Deve instalá-los (ou usar peerDependenciesMeta para opcionais)

Apenas bibliotecas

peerDependenciesMeta

Metadados para peerDependencies, usado para marcar peers como opcionais

Nenhum - afeta apenas o comportamento do gerenciador de pacotes

Apenas bibliotecas

devDependencies

Ferramentas usadas somente durante o desenvolvimento

Nenhum

Apps e bibliotecas

Sobre peerDependenciesMeta

peerDependenciesMeta é um campo que fornece metadados sobre suas peerDependencies. O caso de uso mais comum é marcar peers como opcionais:

  • Peers obrigatórios (padrão): O gerenciador de pacotes avisará se não estiverem instalados

  • Peers opcionais: O gerenciador de pacotes não avisará se estiverem ausentes; seu pacote deve tratar a ausência de forma graciosa

Isto é útil para pacotes que podem funcionar com ou sem certas dependências (por exemplo, um utilitário que funciona com ou sem React, ou uma biblioteca que suporta múltiplos provedores Web3).

Apps vs Bibliotecas

Bibliotecas / Pacotes Compartilhados:

  • Use peerDependencies para pacotes que devem resolver para uma única versão efetiva em tempo de execução (React, ethers, @dcl/schemas)

  • O consumidor (app) fornece essas dependências

  • Previne instalações duplicadas e conflitos de singleton

Apps / Serviços Finais:

  • Frequentemente usam dependencies para pacotes em tempo de execução (React, ethers, etc.)

  • Eles são o consumidor final, então duplicação não é uma preocupação

  • peerDependencies ainda válido se o app puder ser consumido como uma dependência

3. Quando Usar Cada Campo

Referência rápida: Ver Seção 4 para pacotes comuns e seu posicionamento recomendado.

Usar peerDependencies para (Apenas Bibliotecas):

Em bibliotecas/pacotes compartilhados, usar peerDependencies para pacotes que devem resolver para uma única versão efetiva em tempo de execução:

  • React, Redux, wagmi, ethers, viem

  • @dcl/schemas e bibliotecas semelhantes de cruzamento de ecossistema

  • decentraland/connect

  • Drivers de BD ao compartilhar pools

  • Qualquer biblioteca que dependa de singletons ou context

✅ Correto (Biblioteca):

❌ Incorreto (Biblioteca usando dependencies para libs compartilhadas):

Usar dependencies para:

  • Utilitários seguros para duplicar (lodash-es, date-fns)

  • Em apps: Pacotes em tempo de execução como React, ethers (quando o app é o consumidor final)

Importante: Sempre usar versões exatas/fixas em dependencies para segurança.

✅ Correto (Biblioteca):

✅ Correto (App):

peerDependencies opcionais (peerDependenciesMeta)

Para pacotes reutilizáveis que funcionam com ou sem certas dependências, usar peerDependenciesMeta para marcar peers como opcionais:

✅ Correto:

O que isso significa:

  • react estiver obrigatório: O consumidor deve instalá-lo ou o gerenciador de pacotes avisará

  • ethers estiver opcionais: O consumidor não precisa instalá-lo; seu pacote deve verificar sua presença antes de usá-lo

Casos de uso:

  • Pacotes que funcionam tanto em ambientes React quanto não-React

  • Bibliotecas que suportam múltiplos provedores Web3 (ethers, viem, etc.)

  • Utilitários que aumentam outras bibliotecas mas não são obrigatórios

Usar devDependencies para:

  • Ferramentas (TypeScript, ESLint, testadores, bundlers)

Importante: Sempre usar versões exatas/fixas em devDependencies para garantir um ambiente de desenvolvimento consistente na equipe.

✅ Correto:

4. Exemplos

Pacotes que DEVEM ser peerDependencies (contexto compartilhado / singletons)

  • react, react-dom, react-redux, react-router-dom

  • redux, @reduxjs/toolkit

  • ethers, viem, wagmi

  • @dcl/schemas, @dcl/ui-env, @dcl/crypto

  • decentraland-dapps, decentraland-ui, decentraland-ui2, decentraland-connect

  • pg, pg-pool

Pacotes que DEVERIAM ser dependencies (seguros para duplicar)

  • lodash-es, date-fns

  • uuid, nanoid

  • zod, ajv

  • ms, mitt, fp-future

5. Padrões Relacionados

Atualizado