From qe-framework
Builds Vue 3 apps with JavaScript and JSDoc typing instead of TypeScript. Creates components, composables, Vite configs, routing, and Pinia state management with full JSDoc type coverage.
How this skill is triggered — by the user, by Claude, or both
Slash command
/qe-framework:Qvue-expert-jsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Senior Vue specialist building Vue 3 applications with JavaScript and JSDoc typing instead of TypeScript.
Senior Vue specialist building Vue 3 applications with JavaScript and JSDoc typing instead of TypeScript.
<script setup> (no lang="ts"), .mjs modules where needed@typedef, @param, @returns, @type) for full type coverage; then run ESLint with the JSDoc plugin (eslint-plugin-jsdoc) to verify coverage — fix any missing or malformed annotations before proceedingLoad detailed guidance based on context:
| Topic | Reference | Load When |
|---|---|---|
| JSDoc Typing | references/jsdoc-typing.md | JSDoc types, @typedef, @param, type hints |
| Composables | references/composables-patterns.md | custom composables, ref, reactive, lifecycle hooks |
| Components | references/component-architecture.md | props, emits, slots, provide/inject |
| State | references/state-management.md | Pinia, stores, reactive state |
| Testing | references/testing-patterns.md | Vitest, component testing, mocking |
For shared Vue concepts, defer to vue-expert:
vue-expert/references/composition-api.md - Core reactivity patternsvue-expert/references/components.md - Props, emits, slotsvue-expert/references/state-management.md - Pinia storesBasic: Component with JSDoc-typed props and emits
<script setup>
/**
* @typedef {Object} UserCardProps
* @property {string} name - Display name
* @property {number} age - User's age
*/
const props = defineProps({ name: { type: String, required: true }, age: { type: Number, required: true } })
const emit = defineEmits(['select'])
/** @param {string} id */
function handleSelect(id) { emit('select', id) }
</script>
<template><div @click="handleSelect(props.name)">{{ props.name }} ({{ props.age }})</div></template>
Error Handling: Composable with error state
import { ref } from 'vue'
/**
* @typedef {Object} AsyncState
* @property {import('vue').Ref<?any>} data
* @property {import('vue').Ref<?Error>} error
* @property {() => Promise<void>} fetch
*/
export function useAsync(url) {
const data = ref(null), error = ref(null)
async function fetch() {
try { data.value = await (await window.fetch(url)).json() }
catch (e) { error.value = e }
}
return { data, error, fetch }
}
Advanced: Renderless component pattern
<script setup>
const props = defineProps({ items: Array, onSelect: Function })
const selected = ref(null)
</script>
<template>
<slot :items="items" :selected="selected" :select="(item) => { selected = item; props.onSelect?.(item) }" />
</template>
All public functions must use JSDoc with @type annotations:
/**
* Brief description.
* @param {string} name - Parameter description
* @param {number} [count=1] - Optional parameter
* @returns {Promise<Object>} Returns description
* @throws {Error} When condition occurs
*/
export function myFunction(name, count = 1) { ... }
eslint with parserOptions.ecmaVersion: 2022eslint-plugin-vue with vue/multi-word-component-names, vue/no-unused-varseslint-plugin-jsdoc with requireParamType: true, requireReturnType: trueprettier with semi: false, singleQuote: trueeslint . && eslint-plugin-jsdoc --check before commitv-html — Parse user input; use v-text or text contentnpm audit weekly; pin versions in lockfile.env.local for secrets; never commit API keyshref; use DOMPurify if rendering HTML| Wrong | Correct |
|---|---|
const userData = {}; no JSDoc | /** @type {import('./types').User} */ const userData = {} |
Options API with data(), methods | <script setup> + ref(), functions |
el.addEventListener('click', ...) in Vue | @click="handler" binding |
| Global event bus for state | Pinia store or provide/inject |
props.name = 'new' mutation | emit('update:name', 'new') |
<script setup>.mjs extension for ES modules when needed@param and @returns@typedef for complex object shapes shared across files@type annotations for reactive variables<script setup lang="ts">).ts file extensionsrequire() in Vue filesWhen implementing Vue features in JavaScript:
<script setup> (no lang attribute) and JSDoc-typed props/emits@typedef definitions for complex prop or state shapes@param and @returns annotationsVue 3 Composition API, JSDoc, ESM modules, Pinia, Vue Router 4, Vite, VueUse, Vitest, Vue Test Utils, JavaScript ES2022+
npx claudepluginhub inho-team/qe-framework --plugin qe-frameworkCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.