Skilllibrary vue
install
source · Clone the upstream repo
git clone https://github.com/merceralex397-collab/skilllibrary
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/merceralex397-collab/skilllibrary "$T" && mkdir -p ~/.claude/skills && cp -r "$T/08-web-frontend-and-design/vue" ~/.claude/skills/merceralex397-collab-skilllibrary-vue && rm -rf "$T"
manifest:
08-web-frontend-and-design/vue/SKILL.mdsource content
Purpose
Build Vue 3 applications using Composition API with
<script setup>, Pinia for state management, and Vue Router for navigation.
When to use this skill
- writing Vue 3 components with
syntax<script setup> - managing state with Pinia stores (replacing Vuex)
- implementing Vue Router with navigation guards and dynamic routes
- migrating from Options API to Composition API
Do not use this skill when
- building React apps — prefer
react-typescript - building Svelte apps — prefer
svelte - the task is Tailwind styling — prefer
tailwind-shadcn
Procedure
- Create component — use
for auto-imports and less boilerplate.<script setup lang="ts"> - Declare reactive state —
for primitives,const count = ref(0)
for objects.const state = reactive({}) - Computed values —
. Auto-tracks dependencies.const doubled = computed(() => count.value * 2) - Watch effects —
for explicit watching,watch(source, callback)
for auto-tracked effects.watchEffect() - Set up Pinia — create store with
using setup syntax.defineStore('name', () => { ... }) - Configure Router — define routes with
. AddcreateRouter()
guard for auth checks.beforeEach - Composables — extract reusable logic into
functions:use*
,useFetch
,useAuth
.useDebounce - Type props —
. UsedefineProps<{ title: string; count?: number }>()
for default values.withDefaults
Script setup component
<script setup lang="ts"> import { ref, computed, onMounted } from 'vue'; const props = withDefaults(defineProps<{ title: string; initialCount?: number; }>(), { initialCount: 0 }); const emit = defineEmits<{ (e: 'update', value: number): void; }>(); const count = ref(props.initialCount); const doubled = computed(() => count.value * 2); function increment() { count.value++; emit('update', count.value); } onMounted(() => { console.log('Mounted'); }); </script> <template> <div> <h2>{{ title }}</h2> <button @click="increment">{{ count }} ({{ doubled }})</button> </div> </template>
Pinia store
// stores/auth.ts import { defineStore } from 'pinia'; import { ref, computed } from 'vue'; export const useAuthStore = defineStore('auth', () => { const user = ref<User | null>(null); const isLoggedIn = computed(() => user.value !== null); async function login(email: string, password: string) { user.value = await api.login(email, password); } function logout() { user.value = null; } return { user, isLoggedIn, login, logout }; });
Vue Router with guards
const router = createRouter({ history: createWebHistory(), routes: [ { path: '/', component: () => import('./pages/Home.vue') }, { path: '/dashboard', component: () => import('./pages/Dashboard.vue'), meta: { requiresAuth: true } }, ], }); router.beforeEach((to) => { const auth = useAuthStore(); if (to.meta.requiresAuth && !auth.isLoggedIn) { return { path: '/login', query: { redirect: to.fullPath } }; } });
Decision rules
- Always use
— less boilerplate, better type inference, auto-imports.<script setup>
for primitives,ref
for objects — but preferreactive
for consistency (unwrap withref
)..value- Pinia setup syntax over options syntax — mirrors Composition API patterns.
- Lazy-load route components —
for code splitting.() => import('./Page.vue') - Extract shared logic into composables (
functions) — do not duplicate across components.use*
References
Related skills
— alternative frontend frameworksvelte
— React patterns for comparisonreact-typescript
— styling Vue components with Tailwindtailwind-shadcn