@tank/vue-nuxt
1.0.0Skill
Description
Vue 3 and Nuxt 3 production patterns covering script setup, composables, reactive primitives, TypeScript integration, Pinia, data fetching, middleware, plugins, rendering modes, Nitro deployment, and testing.
Triggered by
vue 3nuxt 3composablepiniauseFetchuseAsyncData
Review Recommended
tank install -g @tank/vue-nuxtScan completed — 1 finding
0 critical, 0 high, 1 medium — see security tab for details.
Vue & Nuxt
Core Philosophy
- Composition over options --
<script setup>with Composition API is the standard for Vue 3. Prefer composables for reusable logic extraction over mixins, renderless components, or Options API. - Server-first in Nuxt -- Nuxt renders on the server by default. Use
useFetch/useAsyncDatafor data that needs SSR hydration. Reserve$fetchfor client-only actions (form submissions, mutations). - Type everything -- Use type-based
defineProps<T>()anddefineEmits<T>(). Type composable return values explicitly. UseInjectionKey<T>for provide/inject. - Auto-import with intention -- Nuxt auto-imports composables, utils, and Vue APIs. Rely on it for framework APIs but use explicit imports for third-party code to keep dependency graphs visible.
- Reactivity is the API --
ref()for primitives,reactive()for objects you never reassign,computed()for derived state,watch()for side effects. Match the primitive to the use case.
Quick-Start: Common Problems
"How do I structure a Vue 3 component?"
- Use
<script setup lang="ts">-- noexport default, nosetup()return - Define props with
defineProps<{ title: string }>()(type-based) - Define emits with
defineEmits<{ (e: 'update', value: string): void }>() - Extract reusable logic into
composables/use*.tsfiles -> Seereferences/composition-api.md
"useFetch vs useAsyncData vs $fetch?"
| Situation | Use |
|---|---|
| Page/component data with SSR | useFetch('/api/data') |
| Complex fetch logic with SSR | useAsyncData('key', () => $fetch(...)) |
| Client-only mutations | $fetch('/api/submit', { method: 'POST' }) |
| Non-component context | $fetch() directly |
-> See references/data-fetching.md
"Setup store or option store in Pinia?"
- Default to setup stores -- they compose with other composables naturally
- Use option stores only for simple CRUD state or when migrating from Vuex
- Never access stores outside
<script setup>or composables withoutuseNuxtApp()-> Seereferences/state-management.md
"Which rendering mode for each route?"
Use routeRules in nuxt.config.ts for per-route rendering:
| Route Pattern | Rule | Effect |
|---|---|---|
/ | prerender: true | Static at build time |
/blog/** | isr: 3600 | Regenerate every hour |
/products/** | swr: true | Stale-while-revalidate |
/admin/** | ssr: false | Client-side only |
/api/** | cors: true | CORS headers |
-> See references/rendering-deployment.md
"How do I test Vue/Nuxt components?"
- Use Vitest +
@vue/test-utilsfor unit/component tests - Use
@nuxt/test-utilsfor Nuxt-aware integration tests - Test composables by calling them inside a wrapper component or
withSetup-> Seereferences/testing.md
Decision Trees
Reactive Primitive Selection
| Data Shape | Primitive | Reason |
|---|---|---|
| String, number, boolean | ref() | Simple .value access, template auto-unwraps |
| Object you never reassign | reactive() | No .value, direct property access |
| Derived from other state | computed() | Cached, auto-tracks dependencies |
| Side effect on change | watch() | Explicit source, access old/new values |
| Side effect, auto-track deps | watchEffect() | No explicit source, runs immediately |
Component Communication
| Scenario | Pattern |
|---|---|
| Parent to child data | Props (defineProps) |
| Child to parent events | Emits (defineEmits) |
| Two-way binding | defineModel() (Vue 3.4+) |
| Deep ancestor to descendant | provide() / inject() with InjectionKey |
| Cross-component shared state | Pinia store |
| Cross-composable coordination | Composable importing composable |
Reference Index
| File | Contents |
|---|---|
references/composition-api.md | <script setup>, ref/reactive/computed/watch, lifecycle hooks, composable design patterns, Vue 3.4+ and 3.5+ features |
references/typescript-patterns.md | Type-based defineProps/Emits/Model, typed composables, InjectionKey, template ref typing, vue-tsc, generic components |
references/nuxt-fundamentals.md | Directory structure, auto-imports, plugins, layouts, middleware, runtime config, nuxt.config.ts, error handling |
references/data-fetching.md | useFetch, useAsyncData, $fetch, server routes, API patterns, caching, error handling, serialization |
references/state-management.md | Pinia setup/option stores, store composition, persistence plugins, VueUse composables, SSR state hydration |
references/rendering-deployment.md | SSR/SSG/ISR/SWR, routeRules, Nitro presets, edge rendering, SEO (useHead, useSeoMeta), performance optimization |
references/testing.md | Vitest setup, @vue/test-utils patterns, @nuxt/test-utils, testing composables, testing Pinia stores, MSW mocking |