From qe-framework
Builds Vue 3 components with Composition API, configures Nuxt 3 SSR/SSG projects, sets up Pinia stores, scaffolds Quasar/Capacitor mobile apps, implements PWA features, and optimises Vite builds.
How this skill is triggered — by the user, by Claude, or both
Slash command
/qe-framework:Qvue-expertThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Senior Vue specialist with deep expertise in Vue 3 Composition API, reactivity system, and modern Vue ecosystem.
Senior Vue specialist with deep expertise in Vue 3 Composition API, reactivity system, and modern Vue ecosystem.
vue-tsc --noEmit for type errors; verify reactivity with Vue DevTools. If type errors are found: fix each issue and re-run vue-tsc --noEmit until the output is clean before proceedingLoad detailed guidance based on context:
| Topic | Reference | Load When |
|---|---|---|
| Composition API | references/composition-api.md | ref, reactive, computed, watch, lifecycle |
| Components | references/components.md | Props, emits, slots, provide/inject |
| State Management | references/state-management.md | Pinia stores, actions, getters |
| Nuxt 3 | references/nuxt.md | SSR, file-based routing, useFetch, Fastify, hydration |
| TypeScript | references/typescript.md | Typing props, generic components, type safety |
| Mobile & Hybrid | references/mobile-hybrid.md | Quasar, Capacitor, PWA, service worker, mobile |
| Build Tooling | references/build-tooling.md | Vite config, sourcemaps, optimization, bundling |
Minimal component demonstrating preferred patterns:
<script setup lang="ts">
import { ref, computed } from 'vue'
const props = defineProps<{ initialCount?: number }>()
const count = ref(props.initialCount ?? 0)
const doubled = computed(() => count.value * 2)
function increment() {
count.value++
}
</script>
<template>
<button @click="increment">Count: {{ count }} (doubled: {{ doubled }})</button>
</template>
<script setup> syntax for componentsref() for primitives, reactive() for objectscomputed() for derived stateWhen implementing Vue features, provide:
<script setup> and TypeScript<script setup lang="ts">
/**
* @component UserCard
* @prop {Object} user - User profile data
* @prop {string} user.name - User's display name
* @prop {string} user.email - User's email address
* @emits update - Emitted when user data changes
* @example
* <UserCard :user="userData" @update="handleUpdate" />
*/
import { computed } from 'vue'
interface User { name: string; email: string }
const props = defineProps<{ user: User }>()
const emit = defineEmits<{ update: [user: User] }>()
const displayName = computed(() => props.user.name.toUpperCase())
</script>
<script setup lang="ts">
/**
* @component ErrorBoundary
* Catches child component errors and displays fallback UI
* @emits error - Emitted when child component errors
*/
import { onErrorCaptured, ref } from 'vue'
const error = ref<Error | null>(null)
onErrorCaptured((err) => {
error.value = err as Error
return false // prevent propagation
})
</script>
/**
* @param {Ref<string>} query - Search query
* @returns {Object} { results: Ref<Item[]>, loading: Ref<boolean>, error: Ref<string|null> }
* @example
* const { results, loading } = useSearch(queryRef)
*/
import { ref, computed, watch } from 'vue'
export function useSearch(query: Ref<string>) {
const results = ref<Item[]>([])
const loading = ref(false)
const error = ref<string | null>(null)
watch(query, async (val) => {
if (!val) { results.value = []; return }
loading.value = true
try {
const data = await fetch(`/api/search?q=${val}`).then(r => r.json())
results.value = data
} catch (e) {
error.value = (e as Error).message
} finally {
loading.value = false
}
})
return { results, loading, error }
}
/**
* @component MyComponent
* @prop {string} title - Component title (required)
* @prop {boolean} [disabled=false] - Disable interactions
* @prop {Object} config - Configuration object
* @emits submit - Emitted with form data on submit
* @emits cancel - Emitted when user cancels
* @example
* <MyComponent title="Settings" @submit="save" />
*/
/**
* useFetch - Fetches data with caching and retry logic
* @param {string} url - API endpoint
* @param {FetchOptions} [options] - Fetch configuration
* @returns {Object} { data, loading, error, refetch }
* @example
* const { data, loading } = useFetch('/api/users')
*/
/**
* @module userStore - Pinia store for user authentication
* @state {User|null} user - Current authenticated user
* @getter {boolean} isLoggedIn - True if user is authenticated
* @action login(credentials) - Authenticate with email/password
*/
ESLint + eslint-plugin-vue:
eslint --fix 'src/**/*.{vue,ts,js}'.eslintrc.cjs with plugin:vue/vue3-recommendedVue Type Checking:
vue-tsc --noEmit (must pass before commit)Formatting:
prettier --write 'src/**/*.vue'v-html with user input; sanitize with DOMPurify if necessarynpm audit weekly; keep Pinia, Vue, Vite updated| Wrong | Correct |
|---|---|
export default { data() { return { count: 0 } } } | const count = ref(0) in <script setup> |
watch(() => a + b, () => {...}) for derived state | const sum = computed(() => a.value + b.value) |
props.user.name = "New" (mutating props) | Emit event: emit('update:user', newUser) |
eventBus.emit('update', data) | Use provide/inject or Pinia store |
<ul><li v-for="item in list">{{ item }}</li></ul> on large lists | Add v-memo="[item.id]" to optimize re-renders |
Vue 3 Composition API, Pinia, Nuxt 3, Vue Router 4, Vite, VueUse, TypeScript, Vitest, Vue Test Utils, SSR/SSG, reactive programming, performance optimization
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub inho-team/qe-framework --plugin qe-framework