| name | vue |
| description | Vue 3 Composition API, Nuxt patterns, reactivity system, component architecture, and production development practices |
| layer | domain |
| category | frontend |
| triggers | ["vue","vue 3","nuxt","composition api","vue component","ref()","reactive()","computed()","defineProps","pinia","vue router"] |
| inputs | ["Vue component or page requirements","Composition API pattern questions","Nuxt routing and data fetching","Vue reactivity system guidance"] |
| outputs | ["Vue 3 SFC components with Composition API","Nuxt pages, layouts, and server routes","Composable function implementations","Pinia store patterns"] |
| linksTo | ["typescript-frontend","css-architecture","forms","state-management"] |
| linkedFrom | ["code-writer","architect"] |
| preferredNextSkills | ["typescript-frontend","state-management","forms"] |
| fallbackSkills | ["react","svelte"] |
| riskLevel | low |
| memoryReadPolicy | selective |
| memoryWritePolicy | none |
| sideEffects | [] |
Vue 3 & Nuxt Patterns
Purpose
Provide expert guidance on Vue 3 Composition API, Single File Components (SFC), Nuxt 3, reactivity patterns, composables, and production-grade Vue application development. Focus on <script setup>, TypeScript integration, and modern Vue idioms.
Key Patterns
Script Setup Components
Basic component with props and emits:
<!-- components/Button.vue -->
<script setup lang="ts">
interface Props {
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
loading?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
variant: 'primary',
size: 'md',
loading: false,
});
const emit = defineEmits<{
click: [event: MouseEvent];
}>();
// Slots typing
defineSlots<{
default: () => any;
icon?: () => any;
}>();
function handleClick(e: MouseEvent) {
if (!props.loading) {
emit('click', e);
}
}
</script>
<template>
<button
:class="[
'inline-flex items-center justify-center px-6 py-4 text-base rounded-lg',
'transition-all duration-200 focus-visible:ring-2 focus-visible:ring-offset-2',
variant === 'primary' && 'bg-blue-600 text-white hover:bg-blue-700',
variant === 'secondary' && 'bg-white border border-gray-300 hover:bg-gray-50',
variant === 'ghost' && 'text-gray-600 hover:bg-gray-100',
loading && 'opacity-50 pointer-events-none',
]"
:disabled="loading"
@click="handleClick"
>
<slot name="icon" />
<slot />
</button>
</template>
Reactivity System
ref vs reactive:
<script setup lang="ts">
import { ref, reactive, computed, watch, watchEffect } from 'vue';
// ref — for primitives and values you reassign
const count = ref(0);
const name = ref('');
const isOpen = ref(false);
// reactive — for objects where you mutate properties
const form = reactive({
title: '',
description: '',
tags: [] as string[],
});
// computed — derived values (cached, auto-tracked)
const isValid = computed(() => form.title.length > 0 && form.description.length > 0);
const tagCount = computed(() => form.tags.length);
// Writable computed
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (val: string) => {
const [first, ...rest] = val.split(' ');
firstName.value = first;
lastName.value = rest.join(' ');
},
});
// watch — explicit dependency tracking
watch(count, (newVal, oldVal) => {
console.log(`Count changed: ${oldVal} -> ${newVal}`);
});
// Watch multiple sources
watch([count, name], ([newCount, newName]) => {
// Fires when either changes
});
// Deep watch on reactive object
watch(
() => form.tags,
(newTags) => { /* tags array changed */ },
{ deep: true }
);
// watchEffect — auto-tracks dependencies
watchEffect((onCleanup) => {
if (name.value.length < 2) return;
const controller = new AbortController();
fetchSuggestions(name.value, { signal: controller.signal });
onCleanup(() => controller.abort());
});
</script>