feat: biblioteca inteligente libs/ + 5 novas skills (20 skills total)
NOVAS SKILLS: - next-best-practices v0.1.0 (CLEAN) — Next.js App Router, RSC, caching, data - nextjs-patterns v1.0.0 (CLEAN) — Next.js 15: Server Actions, route handlers - vite v1.0.0 (CLEAN) — env vars, aliases, proxy, CJS compat - uncle-bob v1.0.0 (CLEAN) — Clean Code, SOLID, Clean Architecture - clean-code-review v1.0.0 (CLEAN) — naming, guard clauses, anti-patterns, refactoring - vue v1.0.0 (CLEAN) — Vue framework - vue-composition-api-best-practices v1.0.0 (CLEAN) — composables, Pinia, reactivity BIBLIOTECA INTELIGENTE libs/ (10 dominios, 11 arquivos): - typescript/ — TS safe + generics gotchas - react/ — Next.js App Router + Vite config - vue/ — Composition API + Pinia - linux/ — System diagnostic cheatsheet - database/ — PostgreSQL + MySQL patterns - browser/ — Chromium CLI + E2E testing - security/ — SAST audit (OWASP Top 10) - best-practices/ — Clean Code + SOLID + Clean Architecture - deploy/ — Docker multi-stack + OpenClaw ops - + INDEX.md como guia de navegacao .learnings/ — LRN-20260519-003 criado (biblioteca compartilhada)
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
# Vue 3 — Composition API Best Practices
|
||||
|
||||
> Extraído de skills: `vue` + `vue-composition-api-best-practices`
|
||||
|
||||
## `<script setup>` Padrão Ouro
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// ✅ Importações no topo — tree-shakeable
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
// ✅ Composables começam com `use`
|
||||
const user = useUserStore()
|
||||
const selectedId = ref<number | null>(null)
|
||||
|
||||
// ✅ Estado + getters no mesmo lugar
|
||||
const filteredUsers = computed(() =>
|
||||
user.list.filter(u => u.active)
|
||||
)
|
||||
|
||||
// ✅ Lifecycle no fim
|
||||
onMounted(() => user.fetchAll())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<button v-if="filteredUsers.length > 0" @click="selectedId = null">
|
||||
Clear
|
||||
</button>
|
||||
</template>
|
||||
```
|
||||
|
||||
## Composables — `useXxx` Pattern
|
||||
|
||||
```ts
|
||||
// composables/usePagination.ts
|
||||
export function usePagination<T>(items: T[], pageSize = 20) {
|
||||
const page = ref(1)
|
||||
const totalPages = computed(() => Math.ceil(items.value.length / pageSize))
|
||||
const paginated = computed(() =>
|
||||
items.value.slice((page.value - 1) * pageSize, page.value * pageSize)
|
||||
)
|
||||
return { page, totalPages, paginated }
|
||||
}
|
||||
```
|
||||
|
||||
## <script setup> Deep Dive
|
||||
|
||||
```vue
|
||||
<!-- ✅ BOM — validade automática, minificado -->
|
||||
<script setup lang="ts">
|
||||
defineProps<{ msg: string }>()
|
||||
const emit = defineEmits<{ (e: 'update', id: number): void }>()
|
||||
</script>
|
||||
|
||||
<!-- ❌ RUIM — option API misturado -->
|
||||
<script lang="ts">
|
||||
export default {
|
||||
data() { return { x: 1 } },
|
||||
methods: { /* ... */ }
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## State Management — Pinia
|
||||
```ts
|
||||
// stores/counter.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
export const useCounterStore = defineStore('counter', () => {
|
||||
const count = ref(0)
|
||||
const double = computed(() => count.value * 2)
|
||||
function increment() { count.value++ }
|
||||
return { count, double, increment }
|
||||
})
|
||||
```
|
||||
|
||||
## Reactividade — Principais Armadilhas
|
||||
- `ref` vs `reactive`: use `ref` por padrão (tipagem simples); `reactive` para objetos grandes
|
||||
- Perda de reatividade ao desestruturar — usar `toRefs()` ou `storeToRefs()`
|
||||
- `watch` vs `watchEffect`: `watch` é mais controlado; `watchEffect` é automático mas menos previsível
|
||||
- `v-if` vs `v-show`: `v-if` remove do DOM; `v-show` togglea `display`
|
||||
|
||||
## Type-Safe Vue
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
// Props tipadas — importa de arquivo separado se for reutilizável
|
||||
const props = defineProps<{
|
||||
userId: number
|
||||
items: Item[]
|
||||
requiredValue: string
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'delete', id: number): void
|
||||
(e: 'save', data: FormData): void
|
||||
}>()
|
||||
</script>
|
||||
```
|
||||
|
||||
## Vue Router Traps
|
||||
- `useRoute()` para rota atual — reativa, usar em setup
|
||||
- `useRouter()` para navegação — `router.push('/path')`
|
||||
- Guards: `beforeEach`, `beforeResolve`, `afterEach` — retornar `false` cancela
|
||||
- `<RouterView>` com named views — múltiplas views por rota
|
||||
|
||||
## Common Mistakes
|
||||
- `key` em `v-for` é obrigatório — `v-for="item in items" :key="item.id"`
|
||||
- Ordem de event modifiers importa — `.prevent.stop` ≠ `.stop.prevent`
|
||||
- `Teleport` para modais — `<Teleport to="body">` renderiza fora da árvore
|
||||
Reference in New Issue
Block a user