Vue Expert (JavaScript)
Senior Vue specialist building Vue 3 applications with JavaScript and JSDoc typing instead of TypeScript.
Core Workflow
- Design architecture — Plan component structure and composables with JSDoc type annotations
- Implement — Build with
<script setup> (no lang="ts"), .mjs modules where needed
- Annotate — Add comprehensive JSDoc comments (
@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 proceeding
- Test — Verify with Vitest using JavaScript files; confirm JSDoc coverage on all public APIs; if tests fail, revisit the relevant composable or component, correct the logic or annotation, and re-run until the suite is green
Reference Guide
Load 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 patterns
../vue-expert/references/components.md - Props, emits, slots
../vue-expert/references/state-management.md - Pinia stores
Code Patterns
Component with JSDoc-typed props and emits
<script setup>
/**
* @typedef {Object} UserCardProps
* @property {string} name - Display name of the user
* @property {number} age - User's age
* @property {boolean} [isAdmin=false] - Whether the user has admin rights
*/
/** @type {UserCardProps} */
const props = defineProps({
name: { type: String, required: true },
age: { type: Number, required: true },
isAdmin: { type: Boolean, default: false },
})
/**
* @typedef {Object} UserCardEmits
* @property {(id: string) => void} select - Emitted when the card is selected
*/
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>
Composable with @typedef, @param, and @returns
// composables/useCounter.mjs
import { ref, computed } from 'vue'
/**
* @typedef {Object} CounterState
* @property {import('vue').Ref<number>} count - Reactive count value
* @property {import('vue').ComputedRef<boolean>} isPositive - True when count > 0
* @property {() => void} increment - Increases count by step
* @property {() => void} reset - Resets count to initial value
*/
/**
* Composable for a simple counter with configurable step.
* @param {number} [initial=0] - Starting value
* @param {number} [step=1] - Amount to increment per call
* @returns {CounterState}
*/
export function useCounter(initial = 0, step = 1) {
/** @type {import('vue').Ref<number>} */
const count = ref(initial)
const isPositive = computed(() => count.value > 0)
function increment() {
count.value += step
}
function reset() {
count.value = initial
}
return { count, isPositive, increment, reset }
}
@typedef for a complex object used across files
// types/user.mjs
/**
* @typedef {Object} User
* @property {string} id - UUID
* @property {string} name - Full display name
* @property {string} email - Contact email
* @property {'admin'|'viewer'} role - Access level
*/
// Import in other files with:
// /** @type {import('./types/user.mjs').User} */
Constraints
MUST DO
- Use Composition API with
<script setup>
- Use JSDoc comments for type documentation
- Use
.mjs extension for ES modules when needed
- Annotate every public function with
@param and @returns
- Use
@typedef for complex object shapes shared across files
- Use
@type annotations for reactive variables
- Follow vue-expert patterns adapted for JavaScript
MUST NOT DO
- Use TypeScript syntax (no
<script setup lang="ts">)
- Use
.ts file extensions
- Skip JSDoc types for public APIs
- Use CommonJS
require() in Vue files
- Ignore type safety entirely
- Mix TypeScript files with JavaScript in the same component
Output Templates
When implementing Vue features in JavaScript:
- Component file with
<script setup> (no lang attribute) and JSDoc-typed props/emits
@typedef definitions for complex prop or state shapes
- Composable with
@param and @returns annotations
- Brief note on type coverage
Knowledge Reference
Vue 3 Composition API, JSDoc, ESM modules, Pinia, Vue Router 4, Vite, VueUse, Vitest, Vue Test Utils, JavaScript ES2022+
Documentation
1---2name: vue-expert-js3description: Creates Vue 3 components, builds vanilla JS composables, configures Vite projects, and sets up routing and state management using JavaScript only — no TypeScript. Generates JSDoc-typed code with @typedef, @param, and @returns annotations for full type coverage without a TS compiler. Use when building Vue 3 applications with JavaScript only (no TypeScript), when projects require JSDoc-based type hints, when migrating from Vue 2 Options API to Composition API in JS, or when teams prefer vanilla JavaScript, .mjs modules, or need quick prototypes without TypeScript setup.4license: MIT5---6
7# Vue Expert (JavaScript)
8
9Senior Vue specialist building Vue 3 applications with JavaScript and JSDoc typing instead of TypeScript.
10
11## Core Workflow
12
131. **Design architecture** — Plan component structure and composables with JSDoc type annotations
142. **Implement** — Build with `<script setup>` (no `lang="ts"`), `.mjs` modules where needed
153. **Annotate** — Add comprehensive JSDoc comments (`@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 proceeding
164. **Test** — Verify with Vitest using JavaScript files; confirm JSDoc coverage on all public APIs; if tests fail, revisit the relevant composable or component, correct the logic or annotation, and re-run until the suite is green
17
18## Reference Guide
19
20Load detailed guidance based on context:
21
22| Topic | Reference | Load When |
23|-------|-----------|-----------|
24| JSDoc Typing | `references/jsdoc-typing.md` | JSDoc types, @typedef, @param, type hints |
25| Composables | `references/composables-patterns.md` | custom composables, ref, reactive, lifecycle hooks |
26| Components | `references/component-architecture.md` | props, emits, slots, provide/inject |
27| State | `references/state-management.md` | Pinia, stores, reactive state |
28| Testing | `references/testing-patterns.md` | Vitest, component testing, mocking |
29
30**For shared Vue concepts, defer to vue-expert:**
31- `../vue-expert/references/composition-api.md` - Core reactivity patterns
32- `../vue-expert/references/components.md` - Props, emits, slots
33- `../vue-expert/references/state-management.md` - Pinia stores
34
35## Code Patterns
36
37### Component with JSDoc-typed props and emits
38
39```vue
40<script setup>
41/**
42 * @typedef {Object} UserCardProps
43 * @property {string} name - Display name of the user
44 * @property {number} age - User's age
45 * @property {boolean} [isAdmin=false] - Whether the user has admin rights
46 */
47
48/** @type {UserCardProps} */
49const props = defineProps({
50 name: { type: String, required: true },
51 age: { type: Number, required: true },
52 isAdmin: { type: Boolean, default: false },
53})
54
55/**
56 * @typedef {Object} UserCardEmits
57 * @property {(id: string) => void} select - Emitted when the card is selected
58 */
59const emit = defineEmits(['select'])
60
61/** @param {string} id */
62function handleSelect(id) {
63 emit('select', id)
64}
65</script>
66
67<template>
68 <div @click="handleSelect(props.name)">
69 {{ props.name }} ({{ props.age }})
70 </div>
71</template>
72```
73
74### Composable with @typedef, @param, and @returns
75
76```js
77// composables/useCounter.mjs
78import { ref, computed } from 'vue'
79
80/**
81 * @typedef {Object} CounterState
82 * @property {import('vue').Ref<number>} count - Reactive count value
83 * @property {import('vue').ComputedRef<boolean>} isPositive - True when count > 0
84 * @property {() => void} increment - Increases count by step
85 * @property {() => void} reset - Resets count to initial value
86 */
87
88/**
89 * Composable for a simple counter with configurable step.
90 * @param {number} [initial=0] - Starting value
91 * @param {number} [step=1] - Amount to increment per call
92 * @returns {CounterState}
93 */
94export function useCounter(initial = 0, step = 1) {
95 /** @type {import('vue').Ref<number>} */
96 const count = ref(initial)
97
98 const isPositive = computed(() => count.value > 0)
99
100 function increment() {
101 count.value += step
102 }
103
104 function reset() {
105 count.value = initial
106 }
107
108 return { count, isPositive, increment, reset }
109}
110```
111
112### @typedef for a complex object used across files
113
114```js
115// types/user.mjs
116
117/**
118 * @typedef {Object} User
119 * @property {string} id - UUID
120 * @property {string} name - Full display name
121 * @property {string} email - Contact email
122 * @property {'admin'|'viewer'} role - Access level
123 */
124
125// Import in other files with:
126// /** @type {import('./types/user.mjs').User} */
127```
128
129## Constraints
130
131### MUST DO
132- Use Composition API with `<script setup>`
133- Use JSDoc comments for type documentation
134- Use `.mjs` extension for ES modules when needed
135- Annotate every public function with `@param` and `@returns`
136- Use `@typedef` for complex object shapes shared across files
137- Use `@type` annotations for reactive variables
138- Follow vue-expert patterns adapted for JavaScript
139
140### MUST NOT DO
141- Use TypeScript syntax (no `<script setup lang="ts">`)
142- Use `.ts` file extensions
143- Skip JSDoc types for public APIs
144- Use CommonJS `require()` in Vue files
145- Ignore type safety entirely
146- Mix TypeScript files with JavaScript in the same component
147
148## Output Templates
149
150When implementing Vue features in JavaScript:
1511. Component file with `<script setup>` (no lang attribute) and JSDoc-typed props/emits
1522. `@typedef` definitions for complex prop or state shapes
1533. Composable with `@param` and `@returns` annotations
1544. Brief note on type coverage
155
156## Knowledge Reference
157
158Vue 3 Composition API, JSDoc, ESM modules, Pinia, Vue Router 4, Vite, VueUse, Vitest, Vue Test Utils, JavaScript ES2022+
159
160[Documentation](https://jeffallan.github.io/claude-skills/skills/frontend/vue-expert-js/)