@tank/vue-nuxt
1.0.0Description
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
Download
Review Recommended
tank install @tank/vue-nuxtVue & 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 |