<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Arthur Pedro Spolti</title>
    <description>The latest articles on DEV Community by Arthur Pedro Spolti (@arthur-psp).</description>
    <link>https://dev.to/arthur-psp</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3759955%2Ffed99c82-d772-483b-80be-24450b04948a.png</url>
      <title>DEV Community: Arthur Pedro Spolti</title>
      <link>https://dev.to/arthur-psp</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arthur-psp"/>
    <language>en</language>
    <item>
      <title>Arquitetura Limpa e Injeção de Dependência no Vue.js: Como estou aplicando conceitos de escalabilidade com JavaScript puro</title>
      <dc:creator>Arthur Pedro Spolti</dc:creator>
      <pubDate>Mon, 09 Feb 2026 00:04:27 +0000</pubDate>
      <link>https://dev.to/arthur-psp/arquitetura-limpa-e-injecao-de-dependencia-no-vuejs-como-estou-aplicando-conceitos-de-44jp</link>
      <guid>https://dev.to/arthur-psp/arquitetura-limpa-e-injecao-de-dependencia-no-vuejs-como-estou-aplicando-conceitos-de-44jp</guid>
      <description>&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Então após muita pesquisa e estudo, decidi compartilhar a abordagem que estou aplicando nos meus projetos em &lt;strong&gt;Vue.js&lt;/strong&gt; e &lt;strong&gt;JavaScript&lt;/strong&gt;. Não é uma verdade absoluta, mas é uma solução eficaz e clara - e eu adoraria ouvir o que você acha dela.&lt;/p&gt;




&lt;h2&gt;
  
  
  1.0 Estruturação de Pastas
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnr4se8t40jd5so03o6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpnr4se8t40jd5so03o6.png" alt="Exemplo da estruturação de pastas" width="290" height="514"&gt;&lt;/a&gt;&lt;br&gt;
Nessa abordagem, cada contexto de negócio é isolado em um módulo autossuficiente, dentro de cada um, temos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;data/repository&lt;/code&gt;&lt;/strong&gt;: O repository é a camada que lida com a origem dos dados (nesse caso utilizei uma API pública);&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;domain/usecase&lt;/code&gt;&lt;/strong&gt;: A camada de domínio, é o coração do módulo e não deve depender de nenhuma camada;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;di&lt;/code&gt;&lt;/strong&gt;: Aqui é onde o diferencial entra. Utilizamos o &lt;code&gt;provide&lt;/code&gt; do 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;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;keys&lt;/code&gt;&lt;/strong&gt;: Aqui definimos os símbolos, que servirão como chaves para a injeção de dependência;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;controller&lt;/code&gt;&lt;/strong&gt;: 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;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;view&lt;/code&gt;&lt;/strong&gt;: Camada de apresentação.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2.0 Implementação
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;2.1 &lt;code&gt;data/repository/fetch_company_repository.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2rpo6b92kjhppshug85.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg2rpo6b92kjhppshug85.png" alt="Exemplo de uso do repository" width="800" height="466"&gt;&lt;/a&gt;&lt;br&gt;
Criamos uma instância do axios, recebemos ela aqui no repository, mas sem importá-lo diretamente e retornamos a resposta.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.2 &lt;code&gt;domain/usecase/fetch_company_usecase.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9om5b3pn654zu1nixar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9om5b3pn654zu1nixar.png" alt="Exemplo de uso do usecase" width="800" height="310"&gt;&lt;/a&gt;&lt;br&gt;
Criamos uma função que recebe o &lt;code&gt;repository&lt;/code&gt; por parâmetro.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.3 &lt;code&gt;di/company_di.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8f6yqcrzu1q0v88omtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl8f6yqcrzu1q0v88omtw.png" alt="Exemplo de uso da di" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Nesta etapa, conectamos as camadas que criamos anteriormente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;O &lt;code&gt;repository&lt;/code&gt; recebe a instância global do Axios (configurada com a URL base). Em seguida, o &lt;code&gt;usecase&lt;/code&gt; recebe esse &lt;code&gt;repository&lt;/code&gt;. Mantendo o código desacoplado.&lt;/li&gt;
&lt;li&gt;Criamos uma função que recebe o &lt;code&gt;app&lt;/code&gt; (instância do Vue). Isso permite injetarmos as dependências globalmente ou de forma modular.&lt;/li&gt;
&lt;li&gt;Usamos essas keys (símbolos) para evitar algum tipo de conflito com as strings. Ao executar &lt;code&gt;app.provide(key, instancia)&lt;/code&gt;, estamos dizendo ao Vue: "Sempre que alguém pedir por esta chave, entregue esta instância pronta do Caso de Uso".&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;strong&gt;2.4 &lt;code&gt;keys/company_keys.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floflo3za2fit439sixjs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Floflo3za2fit439sixjs.png" alt="Exemplo de uso das keys" width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nesse arquivo definimos as keys do nosso módulo. Embora o vue permita uma string diretamente no &lt;code&gt;app.provide("key", instancia)&lt;/code&gt;, essa prática é arriscada em projetos escaláveis. Ao centralizar as chaves no objeto, eliminamos o risco de colisões.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.5 &lt;code&gt;di/index.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgzf53yf84hr4gox96fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhgzf53yf84hr4gox96fl.png" alt="di centralizada" width="800" height="266"&gt;&lt;/a&gt;&lt;br&gt;
Para que a injeção de dependências funcione, centralizamos tudo em uma única função que recebe o &lt;code&gt;app&lt;/code&gt; e o repassa para os demais controllers. Garantindo que haja apenas uma chamada na &lt;code&gt;main.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkibwvk7sjfpe1fgj0xd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkibwvk7sjfpe1fgj0xd7.png" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.6 &lt;code&gt;controller/controller.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fux9xrybvmtzyh1lyc6i5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fux9xrybvmtzyh1lyc6i5.png" alt="Exemplo de uso controller" width="800" height="701"&gt;&lt;/a&gt;&lt;br&gt;
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.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2.7 &lt;code&gt;view/company_view.js&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3xse2bos19ftimjsus5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa3xse2bos19ftimjsus5.png" alt="Exemplo da view" width="800" height="683"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;E finalmente, o arquivo &lt;code&gt;.vue&lt;/code&gt; aqui apenas importamos o &lt;code&gt;controller&lt;/code&gt; e montamos o que a tela precisa.&lt;/p&gt;




&lt;h2&gt;
  
  
  3.0 Vantagem
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;"Mas poderíamos simplesmente importar o UseCase direto no controller?" Sim, funcionaria. Mas ao usar &lt;code&gt;provide/inject&lt;/code&gt; 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.&lt;/p&gt;




&lt;h2&gt;
  
  
  Referências e Links úteis:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Inspiração da Estrutura: Este artigo foi baseado na arquitetura apresentada em: &lt;a href="https://dev.to/booscaaa/vuejs-clean-architecture-e-package-by-feature-pattern-56lb"&gt;mestre-da-clean-architeure&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;API utilizada: Para os exemplos do repositório, utilizei a API: &lt;a href="https://app.beeceptor.com/mock-server/dummy-json" rel="noopener noreferrer"&gt;link da api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusão:
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Se você ficou com alguma dúvida , tem outra sugestão de melhoria ou utiliza uma abordagem diferente, adoraria ouvir seu comentário.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
