⚡ Gabriel Caiana
imagem principal do site

Arquitetura Modular com Nuxt Layers em Projetos Vue


O Desafio Invisível que Todo Dev Frontend Enfrenta

Você conhece essa história: começou um projeto Vue pequeno, organizou tudo direitinho - components aqui, pages ali, stores no seu lugar. Três meses depois, você tem 147 componentes, e encontrar aquele ProductCardVariantB.vue virou uma expedição arqueológica.

Pior ainda: você precisa mexer no carrinho de compras, mas os arquivos estão espalhados em 7 pastas diferentes. Um componente aqui, uma store ali, as páginas em outro lugar… e aquela sensação de que a organização que fazia sentido no início agora está atrapalhando seu trabalho.

Este é o problema silencioso da escalabilidade em frontend. E a solução vem de um lugar inesperado: conceitos de arquitetura backend aplicados ao mundo do navegador.

A Inspiração: Monólitos Modulares do Backend

No mundo backend, existe um debate eterno: monólito ou microserviços? Mas arquitetos como Sam Newman e Simon Brown propuseram uma terceira via: o monólito modular.

Como Martin Fowler explica, um monólito modular é “uma aplicação única que mantém uma estrutura interna altamente modularizada”. Você tem os benefícios de modularização (separação de responsabilidades, desenvolvimento independente, fronteiras claras) sem a complexidade operacional de microserviços (múltiplos deploys, comunicação via rede, orquestração).

O Princípio Fundamental

A sacada genial é organizar o código por domínio de negócio em vez de responsabilidade técnica. No backend, isso significa que tudo relacionado a “Pagamentos” fica junto - controllers, services, repositories, models. Tudo sobre “Usuários” em outro módulo. E assim por diante.

Mas… e no frontend?

O Problema da Organização Tradicional em Vue/Nuxt

Vamos ser honestos sobre como 99% dos projetos Vue são organizados hoje:

meu-ecommerce/
├── components/
│   ├── cart/
│   │   ├── CartItem.vue
│   │   ├── CartSummary.vue
│   │   └── CartDrawer.vue
│   ├── product/
│   │   ├── ProductCard.vue
│   │   ├── ProductGallery.vue
│   │   └── ProductReviews.vue
│   └── shared/
│       ├── Button.vue
│       └── Modal.vue
├── pages/
│   ├── products/
│   │   └── [id].vue
│   ├── cart.vue
│   └── index.vue
├── stores/
│   ├── cart.js
│   ├── product.js
│   └── user.js
└── composables/
    ├── useCart.js
    └── useProduct.js

Parece organizado, certo? Mas vamos pensar em um cenário real:

“Preciso implementar uma nova feature no carrinho”

Você vai precisar:

  1. Navegar até components/cart/ para os componentes
  2. Pular para pages/cart.vue para a página
  3. Ir em stores/cart.js para a lógica de estado
  4. Verificar composables/useCart.js para funções auxiliares
  5. Talvez até api/cart.js se tiver separado

São 5 diretórios diferentes para trabalhar em uma única feature. Multiplique isso por cada desenvolvedor do time, cada feature, cada dia… e você entende por que projetos grandes se tornam difíceis de manter.

Nuxt Layers: A Revolução Silenciosa

Com o Nuxt 3, veio uma feature que passou meio despercebida mas que é revolucionária: Nuxt Layers. Como Dave Stewart explica em seu artigo sobre arquitetura modular, Layers permitem reorganizar completamente a estrutura do projeto.

Em vez de organizar por tipo de arquivo, organizamos por domínio:

meu-ecommerce/
├── layers/
│   ├── cart/                    # Tudo sobre carrinho
│   │   ├── components/
│   │   │   ├── CartItem.vue
│   │   │   ├── CartSummary.vue
│   │   │   └── CartDrawer.vue
│   │   ├── pages/
│   │   │   └── cart.vue
│   │   ├── stores/
│   │   │   └── cart.js
│   │   ├── composables/
│   │   │   └── useCart.js
│   │   └── nuxt.config.ts       # Config específica do cart
│   │
│   ├── product/                 # Tudo sobre produtos
│   │   ├── components/
│   │   ├── pages/
│   │   ├── stores/
│   │   └── nuxt.config.ts
│   │
│   └── catalog/                 # Tudo sobre catálogo
│       ├── components/
│       ├── pages/
│       ├── stores/
│       └── nuxt.config.ts
└── nuxt.config.ts               # Config principal

Como Funciona na Prática

Cada layer é como uma “mini-aplicação” Vue. Tem sua própria estrutura, suas próprias configurações, seus próprios módulos. O Nuxt então “costura” tudo junto em tempo de build.

// nuxt.config.ts principal
export default defineNuxtConfig({
  extends: [
    './layers/cart',
    './layers/product',
    './layers/catalog'
  ]
})

E cada layer pode ter sua própria configuração:

// layers/cart/nuxt.config.ts
export default defineNuxtConfig({
  // Módulos específicos do carrinho
  modules: ['@vueuse/nuxt'],

  // Components do carrinho
  components: {
    dirs: [{
      path: './components',
      prefix: 'Cart'  // CartItem, CartSummary, etc.
    }]
  }
})

Os Benefícios Transformadores

1. Coesão Natural de Domínio

Quando você precisa trabalhar no carrinho, tudo está em layers/cart. Não precisa ficar pulando entre pastas. É como ter um mini-projeto dedicado só para aquela feature.

# Trabalhando no carrinho? É só isso:
cd layers/cart
# Todos os arquivos relacionados estão aqui

2. Desenvolvimento Verdadeiramente Paralelo

Com domínios isolados, times diferentes podem trabalhar sem pisar no pé um do outro:

  • Time A trabalhando em layers/checkout
  • Time B refatorando layers/product
  • Time C criando nova feature em layers/recommendations

Menos conflitos no Git, menos “quem mexeu no meu componente?”, menos stress.

3. Onboarding Simplificado

Novo dev no time? Em vez de explicar a arquitetura inteira:

“Você vai cuidar do catálogo. Está tudo em layers/catalog. É como se fosse uma aplicação Vue separada, mas integrada com o resto.”

Pronto. Em 5 minutos a pessoa já está produtiva.

4. Boundaries Naturais e Encapsulamento

Cada layer expõe apenas o que precisa ser público. O resto fica encapsulado:

// layers/cart/index.ts - Interface pública
export { useCart } from './composables/useCart'
export { CartButton } from './components/CartButton'
// CartDrawer, CartLogic, etc. ficam privados

5. Preparação para o Futuro

Hoje você tem um monólito modular. Amanhã, se precisar, pode:

  • Extrair uma layer como pacote NPM
  • Transformar em micro-frontend
  • Mover para um repo separado
  • Criar uma aplicação independente

A arquitetura já está pronta para evolução.

Cenários Onde Brilha (e Onde Não)

Cenários Perfeitos ✅

1. E-commerce Médio/Grande

  • Domínios claros: Catálogo, Produto, Carrinho, Checkout, User
  • Features complexas mas independentes
  • Múltiplos times ou desenvolvedores

2. Aplicações SaaS B2B

  • Dashboard, Reports, Settings, Integrations
  • Cada módulo com suas próprias regras e complexidades
  • Necessidade de evolução independente

3. Portais e Marketplaces

  • Área do vendedor, área do comprador, admin
  • Diferentes experiências e necessidades
  • Times especializados por área

4. Aplicações Multi-tenant

  • Core compartilhado
  • Customizações por cliente em layers separadas
  • Facilita white-label

Onde Talvez Não Faça Sentido ❌

1. Landing Pages e Sites Institucionais

  • Poucos componentes
  • Sem domínios claros de negócio
  • Complexidade desnecessária

2. MVPs e Protótipos

  • Velocidade > Estrutura
  • Mudanças constantes de escopo
  • Time muito pequeno (1-2 devs)

3. Aplicações Hipersimples

  • CRUD básico
  • Menos de 20 componentes
  • Sem perspectiva de crescimento

Comparação com Outras Abordagens

Monorepo com Workspaces

monorepo/
├── packages/
│   ├── cart/
│   ├── product/
│   └── shared/
└── apps/
    └── main-app/

Prós do Monorepo:

  • Separação física total
  • Versionamento independente
  • Pode publicar no NPM

Prós do Nuxt Layers:

  • Menos complexidade de configuração
  • Build único e otimizado
  • Melhor DX (developer experience)
  • HMR funcionando perfeitamente

Micro-frontends

Micro-frontends são o extremo da modularização - aplicações completamente independentes que se juntam no browser.

Quando Micro-frontends fazem sentido:

  • Times completamente independentes
  • Tecnologias diferentes (Vue + React + Angular)
  • Deploy independente é crítico
  • Escala massiva (100+ devs)

Quando Nuxt Layers é melhor:

  • Time único ou poucos times
  • Stack Vue/Nuxt padronizada
  • Quer evitar complexidade de orquestração
  • Performance é prioridade

Implementando na Prática: Exemplo Simples

Vamos ver um exemplo minimalista de como estruturar um blog + loja:

// nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    './layers/base',    // Compartilhados
    './layers/blog',    // Blog com Nuxt Content
    './layers/shop'     // Loja simples
  ]
})
// layers/blog/nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/content'],

  content: {
    sources: {
      blog: {
        prefix: '/blog',
        base: './layers/blog/content'
      }
    }
  }
})
<!-- layers/shop/pages/shop.vue -->
<template>
  <div>
    <h1>Nossa Loja</h1>
    <ProductGrid :products="products" />
    <!-- ProductGrid está em layers/shop/components/ -->
  </div>
</template>

<script setup>
// Tudo local ao domínio shop
import { useShopStore } from '../stores/shop'
const shop = useShopStore()
const products = await shop.loadProducts()
</script>

Migração Gradual: O Segredo do Sucesso

A beleza desta arquitetura é que você não precisa reescrever tudo. Pode migrar gradualmente:

Fase 1: Identificar Domínios

Liste os domínios óbvios da sua aplicação. Geralmente são as “grandes áreas” que os usuários veem.

Fase 2: Criar Layer Base

Mova componentes compartilhados, utils, composables genéricos.

Fase 3: Migrar um Domínio Piloto

Escolha o domínio mais isolado (geralmente algo como “About” ou “Blog”) e migre como teste.

Fase 4: Expandir Gradualmente

Um domínio por vez, conforme o time tem tempo. Não é um big bang, é evolução.

O Futuro é Modular

A arquitetura modular não é apenas uma moda ou uma forma diferente de organizar pastas. É uma mudança fundamental em como pensamos sobre a estrutura de aplicações frontend.

Como Eric Evans explica em Domain-Driven Design, software deve refletir o domínio do negócio. Com Nuxt Layers, finalmente temos uma forma elegante de fazer isso no frontend.

Conclusão: Pronto para o Próximo Passo?

Se você chegou até aqui, provavelmente está pensando: “Ok, a teoria é linda, mas como eu implemento isso de verdade?”

Ótima pergunta! No próximo artigo, vamos sair da teoria e construir um e-commerce completo do zero usando Nuxt Layers. Vamos implementar:

  • Sistema de catálogo com filtros e busca
  • Páginas de produto com galeria e reviews
  • Carrinho de compras com persistência
  • Integração real entre as layers
  • Testes, deploy e otimizações

Com código real, funcionando, que você pode copiar e adaptar.


Recursos para se Aprofundar

  1. Documentação Oficial Nuxt Layers - A fonte definitiva
  2. Nuxt Layers Unwrapped - Artigo detalhado de Dave Stewart
  3. Domain-Driven Design - Eric Evans sobre modelagem por domínio
  4. Building Evolutionary Architectures - Sobre arquiteturas que evoluem