Arquitetura Limpa e Injeção de Dependência no Vue.js: Como estou aplicando conceitos de escalabilidade com JavaScript puro

Arthur Pedro Spolti
2026-02-09T00:04:27Z
Muito se fala sobre arquitetura limpa no Back-end, mas por que o Front-end ainda parece o 'Velho Oeste' quando o assunto é organização?
Recentemente iniciei um projeto de média escala, e minha meta era que fosse organizado, escalável e que seguisse os princípios de arquitetura. Mas infelizmente não encontrei uma comunidade tão ativa e madura, como a do Back-end.
Então após muita pesquisa e estudo, decidi compartilhar a abordagem que estou aplicando nos meus projetos em Vue.js e JavaScript. Não é uma verdade absoluta, mas é uma solução eficaz e clara - e eu adoraria ouvir o que você acha dela.
1.0 Estruturação de Pastas

Nessa abordagem, cada contexto de negócio é isolado em um módulo autossuficiente, dentro de cada um, temos:
-
data/repository: O repository é a camada que lida com a origem dos dados (nesse caso utilizei uma API pública); -
domain/usecase: A camada de domínio, é o coração do módulo e não deve depender de nenhuma camada; -
di: Aqui é onde o diferencial entra. Utilizamos oprovidedo Vue para realizar a inversão de dependência, disponibilizando as instâncias dos Casos de Uso para que qualquer componente do módulo possa consumi-los sem precisar instanciá-las manualmente; -
keys: Aqui definimos os símbolos, que servirão como chaves para a injeção de dependência; -
controller: Onde serão injetados os casos de uso necessários. Ele coordena as chamadas de dados e gerencia o estado reativo que a tela irá consumir; -
view: Camada de apresentação.
2.0 Implementação
2.1 data/repository/fetch_company_repository.js:

Criamos uma instância do axios, recebemos ela aqui no repository, mas sem importá-lo diretamente e retornamos a resposta.
2.2 domain/usecase/fetch_company_usecase.js:

Criamos uma função que recebe o repository por parâmetro.
2.3 di/company_di.js:
Afinal, o que há de tão diferente nessa implementação? O segredo está na composição das dependências antes mesmo delas chegarem à interface.
Nesta etapa, conectamos as camadas que criamos anteriormente:
- O
repositoryrecebe a instância global do Axios (configurada com a URL base). Em seguida, ousecaserecebe esserepository. Mantendo o código desacoplado. - Criamos uma função que recebe o
app(instância do Vue). Isso permite injetarmos as dependências globalmente ou de forma modular. - Usamos essas keys (símbolos) para evitar algum tipo de conflito com as strings. Ao executar
app.provide(key, instancia), estamos dizendo ao Vue: "Sempre que alguém pedir por esta chave, entregue esta instância pronta do Caso de Uso".
2.4 keys/company_keys.js:
Nesse arquivo definimos as keys do nosso módulo. Embora o vue permita uma string diretamente no app.provide("key", instancia), essa prática é arriscada em projetos escaláveis. Ao centralizar as chaves no objeto, eliminamos o risco de colisões.
2.5 di/index.js:

Para que a injeção de dependências funcione, centralizamos tudo em uma única função que recebe o app e o repassa para os demais controllers. Garantindo que haja apenas uma chamada na main.js.
2.6 controller/controller.js:

O controller é o ponto onde a arquitetura se encontra com a reatividade do Vue. O grande diferencial aqui é que ele não 'sequestra' a lógica de busca, em vez disso, ele injeta o caso de uso por meio da chave única, garantindo que a lógica de negócio permaneça isolada e testável.
2.7 view/company_view.js:
E finalmente, o arquivo .vue aqui apenas importamos o controller e montamos o que a tela precisa.
3.0 Vantagem
Ao usarmos essa abordagem temos um sistema extremamente modular. E por estarmos usando JavaScript puro, isso nos dá o poder de uma arquitetura robusta sem a verbosidade ou a necessidade de bibliotecas externas de DI.
"Mas poderíamos simplesmente importar o UseCase direto no controller?" Sim, funcionaria. Mas ao usar provide/inject do Vue, quebramos o acoplamento rígido. Isso transforma nossos componentes em peças de lego, podemos trocar peças (usecase), por uma implementação diferente sem precisar alterar o código da interface.
Referências e Links úteis:
- Inspiração da Estrutura: Este artigo foi baseado na arquitetura apresentada em: mestre-da-clean-architeure
- API utilizada: Para os exemplos do repositório, utilizei a API: link da api
Conclusão:
Essa estrutura foi a solução que encontrei para garantir a escalabilidade do projeto em que estou trabalhando, meu objetivo aqui foi buscar uma 'certeza' a mais de que essa é uma boa abordagem para grandes projetos e, ao mesmo tempo, compartilhar um possível caminho para aqueles que talvez estejam com a mesma dificuldade que eu tive no início. Em invés de confiar cegamente na IA ou padrões pré-estabelecidos, decidi abrir essa abordagem para a comunidade.
Se você ficou com alguma dúvida , tem outra sugestão de melhoria ou utiliza uma abordagem diferente, adoraria ouvir seu comentário.



