Vue.js — один из самых популярных фронтенд-фреймворков (по данным State of JS 2025, его используют 49% разработчиков). Nuxt 3 добавляет серверный рендеринг, file-based routing и автоматические composables. Но даже опытные разработчики тратят часы на шаблонный код: настройка Pinia store, создание компонентов с TypeScript, типизация роутов.
Чтобы ускорить разработку, я собрал 10 промтов для AI-ассистентов (ChatGPT, Claude, Gemini). Каждый промт — готовый шаблон для конкретной задачи: от генерации компонента до миграции Options API на Composition API. Вы просто копируете промт, вставляете в AI и получаете код, который можно сразу использовать в проекте.
1. Генерация компонента с TypeScript и Composition API
Для чего: Создать компонент с пропсами, emits и слотами, используя <script setup lang="ts">.
Промт:
Сгенерируй Vue 3 компонент на Composition API с TypeScript. Компонент должен:
- Принимать пропсы: title (string, required), items (array of {id: number, name: string}, default: []), loading (boolean, default: false)
- Эмитить события: 'update:title' (with string), 'select' (with number)
- Иметь слот default и слот 'footer'
- Использовать v-model через computed
- Не использовать Options API
- Добавить стили scoped
- Импортировать defineProps, defineEmits, computed из 'vue'
Пример использования:
<script setup lang="ts">
import { computed } from 'vue'
interface Item {
id: number
name: string
}
const props = withDefaults(defineProps<{
title: string
items?: Item[]
loading?: boolean
}>(), {
items: () => [],
loading: false
})
const emit = defineEmits<{
(e: 'update:title', value: string): void
(e: 'select', id: number): void
}>()
const localTitle = computed({
get: () => props.title,
set: (val: string) => emit('update:title', val)
})
</script>
2. Композабл для работы с API (useFetch с кэшированием)
Для чего: Создать composable для запросов к бэкенду с автоматическим кэшированием и обработкой ошибок.
Промт:
Напиши composable useApi для Nuxt 3, который:
- Принимает URL и опции (method, body, headers)
- Использует useFetch из Nuxt
- Кэширует результат на 5 минут через ключ в sessionStorage
- Возвращает { data, error, pending, refresh }
- Добавь очистку кэша по ключу
- Обрабатывает ошибки сети и парсинга JSON
- Используй TypeScript с дженериками
Пример:
export function useApi<T>(url: string, options?: { method?: string; body?: any; headers?: Record<string, string> }) {
const cacheKey = `api_${url}_${JSON.stringify(options)}`
const cached = sessionStorage.getItem(cacheKey)
if (cached) {
return { data: ref(JSON.parse(cached)), error: ref(null), pending: ref(false), refresh: () => {} }
}
const { data, error, pending, refresh } = useFetch<T>(url, options)
watchEffect(() => {
if (data.value) {
sessionStorage.setItem(cacheKey, JSON.stringify(data.value))
setTimeout(() => sessionStorage.removeItem(cacheKey), 5 * 60 * 1000)
}
})
return { data, error, pending, refresh }
}
3. Pinia store с TypeScript и плагином persist
Для чего: Создать store для управления состоянием пользователя с сохранением в localStorage.
Промт:
Сгенерируй Pinia store 'useUserStore' для Nuxt 3 с TypeScript и persist (используй @pinia-plugin-persistedstate). Store должен содержать:
- state: user (null
| {id: number, name: string, email: string}), token (string | null), isAuthenticated (boolean)
- getters: isLoggedIn (возвращает true если token есть), userName (возвращает name или 'Гость')
- actions: login(email, password) — имитирует запрос к API, logout() — очищает state
- persist: только token и user
- Использовать defineStore
Пример:
export const useUserStore = defineStore('user', {
state: () => ({
user: null as { id: number; name: string; email: string } | null,
token: null as string | null,
}),
getters: {
isLoggedIn: (state) => !!state.token,
userName: (state) => state.user?.name || 'Гость',
},
actions: {
async login(email: string, password: string) {
const { data } = await $fetch('/api/login', { method: 'POST', body: { email, password } })
this.token = data.token
this.user = data.user
},
logout() {
this.token = null
this.user = null
},
},
persist: {
pick: ['token', 'user'],
storage: persistedState.localStorage,
},
})
4. Middleware для защиты роутов
Для чего: Создать middleware, который проверяет аутентификацию и редиректит на страницу логина.
Промт:
Напиши Nuxt 3 middleware 'auth.ts', который:
- Проверяет useUserStore().isLoggedIn
- Если не авторизован, редиректит на /login с query-параметром redirect (текущий путь)
- Если авторизован и путь /login, редиректит на /dashboard
- Работает как на клиенте, так и на сервере (используй useRouter и useRoute)
- Добавь обработку ошибок (если store не инициализирован)
Пример:
export default defineNuxtRouteMiddleware((to) => {
const userStore = useUserStore()
if (process.server) {
// На сервере store может быть пустым — пропускаем
return
}
if (to.path === '/login' && userStore.isLoggedIn) {
return navigateTo('/dashboard')
}
if (to.path !== '/login' && !userStore.isLoggedIn) {
return navigateTo(`/login?redirect=${to.fullPath}`)
}
})
5. Кастомный плагин для глобальных функций
Для чего: Создать плагин, который добавляет глобальный helper для форматирования дат.
Промт:
Создай Nuxt 3 плагин 'format-date.ts', который:
- Использует Intl.DateTimeFormat
- Добавляет в nuxtApp.provide функцию $formatDate(date, locale?, options?)
- По умолчанию locale = 'ru-RU', options = { day: 'numeric', month: 'long', year: 'numeric' }
- Обрабатывает null/undefined (возвращает '')
- Имеет автокомплит через расширение модуля (declare module '#app')
Пример:
export default defineNuxtPlugin(() => {
const formatDate = (date: Date
| string | null | undefined, locale = 'ru-RU', options?: Intl.DateTimeFormatOptions) => {
if (!date) return ''
const d = new Date(date)
if (isNaN(d.getTime())) return ''
return new Intl.DateTimeFormat(locale, options || { day: 'numeric', month: 'long', year: 'numeric' }).format(d)
}
return {
provide: {
formatDate
}
}
})
declare module '#app' {
interface NuxtApp {
$formatDate(date: Date
| string | null | undefined, locale?: string, options?: Intl.DateTimeFormatOptions): string
}
}
6. Кастомная директива v-focus
Для чего: Создать директиву, которая автоматически фокусирует элемент при монтировании.
Промт:
Напиши Vue 3 директиву v-focus, которая:
- При монтировании элемента устанавливает на него фокус
- Работает с input, textarea, select
- Если передан модификатор .delay, фокус устанавливается через 500ms
- Поддерживает аргумент: v-focus:delay="1000" для кастомной задержки
- Используй mounted и updated хуки
- Типизируй с помощью DirectiveBinding
Пример:
export const vFocus = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
const delay = binding.arg === 'delay' ? (binding.value || 500) : 0
setTimeout(() => el.focus(), delay)
},
updated(el: HTMLElement, binding: DirectiveBinding) {
if (binding.value !== binding.oldValue) {
const delay = binding.arg === 'delay' ? (binding.value || 500) : 0
setTimeout(() => el.focus(), delay)
}
}
}
7. Композабл для Intersection Observer (ленивая загрузка)
Для чего: Создать composable для отслеживания видимости элемента (например, для lazy loading изображений).
Промт:
Создай composable useIntersectionObserver, который:
- Принимает ref на элемент
- Возвращает { isVisible, entry, observe, unobserve }
- Использует IntersectionObserver с options (root, rootMargin, threshold)
- Автоматически отключается после первого срабатывания (once: true)
- Работает в SSR безопасно (проверяет window)
- Написан на TypeScript
Пример:
export function useIntersectionObserver(
target: Ref<HTMLElement | null>,
options?: IntersectionObserverInit & { once?: boolean }
) {
const isVisible = ref(false)
const entry = ref<IntersectionObserverEntry | null>(null)
let observer: IntersectionObserver | null = null
const observe = () => {
if (!window || !target.value) return
observer = new IntersectionObserver(([e]) => {
isVisible.value = e.isIntersecting
entry.value = e
if (options?.once && e.isIntersecting) {
unobserve()
}
}, options)
observer.observe(target.value)
}
const unobserve = () => {
observer?.disconnect()
observer = null
}
onMounted(observe)
onUnmounted(unobserve)
return { isVisible, entry, observe, unobserve }
}
8. Миграция Options API на Composition API
Для чего: Преобразовать старый компонент с Options API в современный Composition API.
Промт:
Перепиши следующий Vue 2 компонент на Vue 3 Composition API с TypeScript. Используй <script setup>. Сохрани всю функциональность:
- data: count (0), message ('hello')
- computed: doubleCount (count * 2)
- watch: count (логировать при изменении)
- methods: increment(), updateMessage(newMsg)
- mounted: вывести 'Component mounted'
- props: title (string, required)
- emits: 'update:count'
Исходный компонент:
export default {
props: { title: String },
data() { return { count: 0, message: 'hello' } },
computed: { doubleCount() { return this.count * 2 } },
watch: { count(val) { console.log(val) } },
methods: { increment() { this.count++; this.$emit('update:count', this.count) }, updateMessage(msg) { this.message = msg } },
mounted() { console.log('Component mounted') }
}
Пример результата:
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
const props = defineProps<{ title: string }>()
const emit = defineEmits<{ (e: 'update:count', value: number): void }>()
const count = ref(0)
const message = ref('hello')
const doubleCount = computed(() => count.value * 2)
watch(count, (val) => console.log(val))
function increment() {
count.value++
emit('update:count', count.value)
}
function updateMessage(msg: string) {
message.value = msg
}
onMounted(() => console.log('Component mounted'))
</script>
9. Настройка динамических маршрутов в Nuxt
Для чего: Создать страницу с динамическими параметрами и middleware для проверки прав.
Промт:
Сгенерируй структуру страниц для Nuxt 3 с динамическими маршрутами:
- Страница /products/[id] с параметром id
- Страница /products/[id]/edit с middleware 'auth' и параметром id
- Внутри страниц используй useRoute() для получения id
- Добавь validate() для проверки, что id — число
- Компонент страницы должен быть типизирован
Пример для pages/products/[id].vue:
<script setup lang="ts">
const route = useRoute()
const id = computed(() => Number(route.params.id))
const { data: product, error } = await useFetch(`/api/products/${id.value}`)
if (error.value) {
throw createError({ statusCode: 404, statusMessage: 'Product not found' })
}
definePageMeta({
validate: (route) => {
return !isNaN(Number(route.params.id))
}
})
</script>
<template>
<div>
<h1>{{ product?.name }}</h1>
<p>{{ product?.description }}</p>
</div>
</template>
10. Кастомный Nuxt модуль
Для чего: Создать простой модуль, который добавляет глобальный компонент и композабл.
Промт:
Напиши минимальный Nuxt 3 модуль 'my-module', который:
- Регистрирует глобальный компонент 'MyButton' из ./runtime/components/MyButton.vue
- Добавляет композабл useMyHelper из ./runtime/composables/useMyHelper.ts
- Использует defineNuxtModule из 'nuxt/kit'
- Имеет опцию prefix (по умолчанию 'My')
- Версионирован (package.json с name и version)
Пример модуля:
import { defineNuxtModule, addComponent, addImportsDir } from '@nuxt/kit'
import { name, version } from '../package.json'
export default defineNuxtModule({
meta: { name, version },
defaults: { prefix: 'My' },
setup(options) {
addComponent({
name: `${options.prefix}Button`,
filePath: resolve(__dirname, './runtime/components/MyButton.vue')
})
addImportsDir(resolve(__dirname, './runtime/composables'))
}
})
Эти промты сэкономят вам часы рутинной работы. Скопируйте нужный, вставьте в AI и получите готовый код. А если хотите углубиться — перечитайте официальную документацию Vue 3 и Nuxt 3: там много деталей, которые не влезли в промты.
Комментарии