Vue 3 FSD Development
Guidelines para desenvolvimento Vue 3 seguindo arquitetura Feature-Sliced Design (FSD) adaptada.
Princípios Fundamentais
- •Separação de Responsabilidades: Cada camada tem responsabilidade única e bem definida
- •Isolamento de Features: Features são auto-contidas e independentes
- •Reutilização Inteligente: Widgets e shared para código reutilizável
- •Performance First: Lazy loading e code splitting por padrão
- •Type Safety: TypeScript em todos os arquivos
Arquitetura FSD
Estrutura de camadas (ordem de dependência):
code
app/ → pages/ → features/ → widgets/ → shared/
Regras de dependência:
- •
app/não depende de nenhuma camada - •
pages/pode importar defeatures/,widgets/,shared/ - •
features/pode importar dewidgets/,shared/ - •
widgets/pode importar deshared/ - •
shared/não depende de outras camadas
NUNCA:
- •❌ Features importando de
pages/ - •❌ Widgets importando de
features/oupages/ - •❌ Shared importando de qualquer outra camada
Para detalhes completos, veja architecture.md.
Estrutura de Features
Cada feature segue esta estrutura:
code
features/[feature-name]/ ├── index.vue # Componente principal ├── model/ # Lógica de negócio │ ├── [feature]Schema.ts # Schema Zod │ └── use[Feature].ts # Composable ├── ui/ # Componentes UI específicos │ └── [component]/ │ ├── index.vue │ └── __tests__/ └── store/ # Store Pinia (se necessário)
Diretrizes:
- •Uma feature = um domínio de negócio
- •Lógica sempre em
model/ - •UI específica em
ui/ - •Testes junto ao código em
__tests__/
Lazy Loading Obrigatório
Rotas: Sempre usar dynamic imports:
typescript
component: () => import('@/pages/users/UsersView.vue')
Features pesadas: Lazy load quando possível:
vue
<script setup>
const HeavyComponent = defineAsyncComponent(() =>
import('@/features/heavy-feature/index.vue')
)
</script>
Mocks condicionais: Lazy load de MSW:
typescript
if (import.meta.env.VITE_ENABLE_MOCK_SERVER === 'true') {
const { worker } = await import('../shared/mocks/browser.ts')
worker.start()
}
Para otimizações avançadas, veja performance.md.
Padrões de Código
Composables com Vue Query
typescript
import { useMutation } from '@tanstack/vue-query'
import { toast } from 'vue-sonner'
import { postLogin as postLoginService } from '@/shared/api/auth-api/postLogin'
import type { Payload } from '@/shared/api/auth-api/types/postLogin.types'
const postLogin = () => {
const { isPending, isError, error, isSuccess, mutate } = useMutation({
mutationFn: (payload: Payload) =>
postLoginService(payload).catch((error) =>
toast.error(error?.response?.data?.message || 'Erro desconhecido.'),
),
})
return { isPending, isError, error, isSuccess, mutate }
}
export function useLogin() {
return { postLogin }
}
APIs
typescript
import { axiosClient } from '../config/http-client'
import type { Payload, Response } from './types/postLogin.types'
export async function postLogin(payload: Payload): Promise<Response> {
const response = await axiosClient.request<Response>({
endpoint: 'login',
method: 'POST',
body: payload,
})
return response.data
}
Validação Zod
typescript
import { z } from 'zod'
const loginSchema = z.object({
email: z.string().email('Email inválido'),
password: z.string().min(6, 'Senha deve ter no mínimo 6 caracteres'),
})
export type LoginFormData = z.infer<typeof loginSchema>
Para mais padrões, veja patterns.md.
Boas Práticas
✅ FAZER
- •Usar Composition API com
<script setup> - •Tipar tudo com TypeScript
- •Separar tipos em arquivos
types/ - •Usar
cn()para merge de classes Tailwind - •Implementar error handling em composables
- •Usar Vue Query para estado servidor
- •Usar Pinia apenas para estado cliente global
- •Testar features junto com o código
❌ NÃO FAZER
- •Misturar lógica de negócio com UI
- •Criar dependências circulares entre camadas
- •Importar features em widgets
- •Usar
anyem TypeScript - •Hardcode de valores (usar env vars)
- •Lógica complexa em templates
- •Mutar props diretamente
- •Criar stores Pinia para estado local
Para lista completa, veja best-practices.md.
Performance
Code Splitting
- •Rotas sempre lazy loaded
- •Features pesadas com
defineAsyncComponent - •Bibliotecas grandes importadas dinamicamente
Vue Query
- •Configurar
staleTimeegcTimeapropriadamente - •Usar
queryKeyreativo para invalidação automática - •Implementar paginação com
currentPageeperPage
Renderização
- •Usar
v-showpara toggle frequente - •Usar
v-ifpara renderização condicional pesada - •Evitar watchers desnecessários
- •Usar
computedpara valores derivados
Para otimizações avançadas, veja performance.md.
Nomenclatura
- •Componentes: PascalCase (
LoginView.vue,UserDialog.vue) - •Composables: camelCase com
use(useLogin.ts,useListUsers.ts) - •Stores: camelCase com
use(useAuthStore) - •APIs: camelCase com verbo (
postLogin.ts,getAllUsers.ts) - •Features: kebab-case (
login-auth/,handle-users/) - •Tipos: PascalCase (
Payload,Response,User)
Imports
- •Sempre usar alias
@/parasrc/ - •Ordenação automática via ESLint
simple-import-sort - •Agrupar: externos → internos → tipos
typescript
import { useMutation } from '@tanstack/vue-query'
import { toast } from 'vue-sonner'
import { postLogin as postLoginService } from '@/shared/api/auth-api/postLogin'
import type { Payload } from '@/shared/api/auth-api/types/postLogin.types'
Recursos Adicionais
- •architecture.md - Detalhes sobre FSD e estrutura
- •best-practices.md - Boas práticas e anti-patterns
- •performance.md - Lazy loading e otimizações
- •patterns.md - Padrões de código específicos