Mk vue
Skill ngocsangyem/MeowKit/packages/mewkit/src/migrate/modules/cursor/root/.cursor/skills/mk-vue
Vue 3 authoring/review: components, composables, reactivity, Pinia, Pinia Colada, file routing, forms. Composition API + script setup. Auto-activates on .vue files. Deep review: mk:vue-best-practices.From its SKILL.md
npx -y skills add ngocsangyem/MeowKit --skill mk-vueAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 14 stars14 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
8.1 KB, ~1.9k tokens by cl100k_base, as published. Nobody here has run it
Vue 3
Vue 3 patterns — Composition API + <script setup lang="ts">, Pinia, Pinia
Colada, file-based routing, and performance. Single entrypoint routing to focused references.
Use
npx chub search vuefor relevant documentation packages within the Context Hub.
When to Use
Auto-activate on: .vue files, Vue 3 Composition API, <script setup>, Pinia stores,
Pinia Colada queries/mutations, Vue Router file-based routes, composables.
Explicit: the vue skill [concern]
Deep best practices: for a thorough best-practices review/recommendations pass or the
full ordered workflow — built-in components (Teleport/Suspense/KeepAlive/Transition),
animation techniques, optional features, and the performance pass — use mk:vue-best-practices.
This skill stays the everyday quick-reference.
Do NOT invoke for: deep best-practices review/workflow (use mk:vue-best-practices),
TypeScript fundamentals (use mk:typescript), React (use mk:react-patterns), Angular (use
mk:angular), visual design (use mk:frontend-design), testing (use mk:testing / mk:qa;
Vue test design/review → mk:vue-testing-best-practices).
Core Rules (always apply)
Follow the repository's established conventions first. When it has no convention, use these defaults; project requirements may override them. Everything else is in the references.
<script setup lang="ts">only — never Options API, neverdefineComponent()wrapper.typeoverinterfacefor defining object/prop shapes; keep types alongside the code.- Arrow functions for methods and callbacks.
- Named exports over default exports — except composables, which use
export default. - PascalCase component names, kebab-case file names (
UserProfileinuser-profile.vue); composables arecamelCasewithuseprefix (useAuth). - Name general → specific:
SearchButtonClear.vue, notClearSearchButton.vue. - TailwindCSS classes, not manual CSS; never hard-code colors — use the Tailwind color system.
- Comments explain why, not what.
ref()for primitives,reactive()only for complex objects;computed()for derived state.- Never
v-htmlwith user-provided content — XSS vector (seemk:security rules).
Data Layer (conditional default)
When the project depends on @pinia/colada, it is the preferred async/data-fetching layer
— see references/pinia-colada.md. Otherwise use plain Pinia stores + composables for state.
Pinia stores hold global UI/app state; data fetching belongs in Pinia Colada when present.
When to Read Each Reference
Read one level deep from this file. Read multiple when a task spans topics.
| Task involves | Read |
|---|---|
Components, props/emits, slots, defineModel, naming, templates | references/components.md |
Composables (use*), shared reactive logic | references/composables.md |
ref/reactive/computed/watch, toRefs, performance | references/reactivity-performance.md |
Global state with Pinia setup stores, storeToRefs | references/state-pinia.md |
Pinia Colada core: keys, defineQueryOptions, useQuery, mutations | references/pinia-colada.md |
| Optimistic updates, infinite/paginated queries, SSR, cancellation | references/pinia-colada-advanced.md |
| Pinia Colada plugins (retry, delay, auto-refetch, persister, hooks) | references/pinia-colada-plugins.md |
Direct cache access: getQueryData/setQueryData/invalidateQueries | references/pinia-colada-cache.md |
File-based routing, route groups, params, definePage, typed router | references/routing-pages.md |
| Project stack, structure, commands, conventions, docs research | references/project-standards.md |
3.4/3.5 core APIs: useId, nextTick, flush timing, watch once/deep, onWatcherCleanup | references/core-new-apis.md |
<script setup> compiler macros — defineOptions, withDefaults, generic components | references/script-setup-macros.md |
Advanced reactivity: effectScope, customRef, triggerRef, markRaw, shallowReadonly | references/advanced-patterns.md |
Gotchas
- Destructuring
reactive()loses reactivity —const { count } = reactive({ count: 0 })makescounta plain number; keep the reactive object intact, or usetoRefs(), orref(). storeToRefs()required when destructuring Pinia state —const { user } = useAuthStore()gives a non-reactive snapshot; useconst { user } = storeToRefs(useAuthStore()). Methods are destructured directly from the store (not throughstoreToRefs).- Parent
refaccess needsdefineExpose()—childRef.value.method()returnsundefinedunless the child<script setup>explicitlydefineExpose({ method }). - Use
:slotted()not:deep()for slotted content — slot content comes from the parent scope, so:deep(.child-class)in a scoped style block does not match it; use:slotted(.child-class). watchEffectcleanup race on fast re-renders — register cleanup to cancel async work:watchEffect((onCleanup) => { onCleanup(() => controller.abort()) }), or a fast prop change starts a second effect before the first resolves and writes stale state.- Pinia store not hydrated in SSR — calling
useMyStore()outside a component setup context (e.g. a top-level module) creates an instance disconnected from the SSR app; call stores insidesetup()or pass thepiniainstance explicitly:useMyStore(pinia). - Query keys must depend on ALL variables used in the query function — a key that omits a variable serves stale cached data when that variable changes (Pinia Colada).
- Dynamic query keys need a getter, not a plain value — pass
key: () => [...]so the key re-evaluates reactively; a plain array snapshot never updates. - Prefer
refresh()overrefetch()—refresh()reuses in-flight requests and respectsstaleTime;refetch()always forces a new fetch. - Avoid
index.vueroute files — use a named group likepages/(home).vuefor a meaningful route name. - Use explicit route param names —
userIdnotid,postSlugnotslug, for type-safe, self-documenting routes. - Watching a destructured prop needs a getter —
const { count } = defineProps()stays reactive in templates, butwatch(count, ...)watches a snapshot; usewatch(() => count, ...)(references/core-new-apis.md). onWatcherCleanup()must be called synchronously — invoking it after anawaitthrows, since the active-watcher context is gone; use theonCleanupcallback param for post-await cancellation (references/core-new-apis.md).
Anti-Patterns
| Don't | Do Instead |
|---|---|
Options API (data(), methods:) | Composition API <script setup> |
this.$store / Vuex | Pinia with setup store syntax |
| Direct store state destructuring | storeToRefs(useMyStore()) |
v-html with dynamic content | v-text or sanitized rendering |
reactive() for primitives | ref() for primitives |
| Watchers when computed works | computed() for derived state |
| Global event bus | provide/inject or Pinia |
defineComponent() wrapper | <script setup> directly |
Workflow Integration
Auto-activates during Build when a Vue project is detected (.vue files, vue in
package.json). Loaded by the developer agent alongside mk:typescript.
What ships with it: 13 files
52.8 KB alongside SKILL.md
references/
- advanced-patterns.md5.0 KB
- components.md4.5 KB
- composables.md1.9 KB
- core-new-apis.md4.9 KB
- pinia-colada-advanced.md6.7 KB
- pinia-colada-cache.md2.4 KB
- pinia-colada.md6.9 KB
- pinia-colada-plugins.md5.5 KB
- project-standards.md3.1 KB
- reactivity-performance.md2.7 KB
- routing-pages.md2.8 KB
- script-setup-macros.md4.1 KB
- state-pinia.md2.3 KB