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:
- Navegar até
components/cart/
para os componentes - Pular para
pages/cart.vue
para a página - Ir em
stores/cart.js
para a lógica de estado - Verificar
composables/useCart.js
para funções auxiliares - 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
- Documentação Oficial Nuxt Layers - A fonte definitiva
- Nuxt Layers Unwrapped - Artigo detalhado de Dave Stewart
- Domain-Driven Design - Eric Evans sobre modelagem por domínio
- Building Evolutionary Architectures - Sobre arquiteturas que evoluem
Top comments (1)
Modular frontend architecture like Nuxt Layers is transformative for SaaS projects, enabling natural domain cohesion and parallel development that scales teams without sacrificing UX consistency.