Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.9 KiB
3.9 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Follow Composable Naming Convention and Return Pattern | MEDIUM | Inconsistent composable patterns lead to confusing APIs and reactivity issues when destructuring | best-practice |
|
Follow Composable Naming Convention and Return Pattern
Impact: MEDIUM - Vue composables should follow established conventions: prefix names with "use" and return plain objects containing refs (not reactive objects). Returning reactive objects causes reactivity loss when destructuring, while inconsistent naming makes code harder to understand.
Task Checklist
- Name composables with "use" prefix (e.g.,
useMouse,useFetch,useAuth) - Return a plain object containing refs, not a reactive object
- Allow both destructuring and object-style access
- Document the returned refs for consumers
Incorrect:
// WRONG: No "use" prefix - unclear it's a composable
export function mousePosition() {
const x = ref(0)
const y = ref(0)
return { x, y }
}
// WRONG: Returning reactive object - destructuring loses reactivity
export function useMouse() {
const state = reactive({
x: 0,
y: 0
})
// When consumer destructures: const { x, y } = useMouse()
// x and y become plain values, not reactive!
return state
}
// WRONG: Returning single ref directly - inconsistent API
export function useCounter() {
const count = ref(0)
return count // Consumer must use .value everywhere
}
Correct:
// CORRECT: "use" prefix and returns plain object with refs
export function useMouse() {
const x = ref(0)
const y = ref(0)
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// Return plain object containing refs
return { x, y }
}
// Consumer can destructure and keep reactivity
const { x, y } = useMouse()
watch(x, (newX) => console.log('x changed:', newX)) // Works!
// Or use as object if preferred
const mouse = useMouse()
console.log(mouse.x.value)
Using reactive() Wrapper for Auto-Unwrapping
If consumers prefer auto-unwrapping (no .value), they can wrap the result:
import { reactive } from 'vue'
import { useMouse } from './composables/useMouse'
// Wrapping in reactive() links the refs
const mouse = reactive(useMouse())
// Now access without .value
console.log(mouse.x) // Auto-unwrapped, still reactive
// But DON'T destructure from this!
const { x } = reactive(useMouse()) // WRONG: loses reactivity again
Pattern: Returning Both State and Actions
// Composable with state AND methods
export function useCounter(initialValue = 0) {
const count = ref(initialValue)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
function decrement() {
count.value--
}
function reset() {
count.value = initialValue
}
// Return all refs and functions in plain object
return {
count,
doubleCount,
increment,
decrement,
reset
}
}
// Usage
const { count, doubleCount, increment, reset } = useCounter(10)
Naming Convention Examples
| Good Name | Bad Name | Reason |
|---|---|---|
useFetch |
fetch |
Conflicts with native fetch |
useAuth |
authStore |
"Store" implies Pinia/Vuex |
useLocalStorage |
localStorage |
Conflicts with native API |
useFormValidation |
validateForm |
Sounds like a one-shot function |
useWindowSize |
getWindowSize |
"get" implies synchronous getter |