Що таке plugins в Nuxt?
Nuxt plugins (плагіни Nuxt) - це файли в директорії plugins/, які виконуються один раз під час ініціалізації застосунку, реєструючи Vue-плагіни, утиліти або глобальні хелпери до того, як монтується будь-який компонент.
Теорія
TL;DR
- Уяви плагіни як наземну команду аеропорту: вони готують сервіси (auth, повідомлення, API-клієнти) до старту застосунку, щоб кожна сторінка мала до них доступ
- Плагіни виконуються один раз при старті; composables - на кожен компонент; middleware - на кожен роут
- Потрібна Vue-інтеграція (
vueApp.use()) або глобальний inject (provide) - потрібен плагін - Суфікс
.client.tsдля браузерного коду,.server.tsдля SSR - Nuxt сортує плагіни за алфавітом; числові префікси (
01.auth.ts) контролюють порядок
Швидкий приклад
// plugins/toast.client.ts - виконується лише в браузері
import Toast from 'vue-toastification'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast, { timeout: 3000 })
// Toast зареєстровано глобально у Vue-застосунку
})
// У будь-якому компоненті чи сторінці:
const { $toast } = useNuxtApp()
$toast.success('Збережено!')Один раз зареєстрував - доступно всюди. Жодних окремих імпортів у компонентах.
Головна відмінність
Плагіни виконуються під час фази старту Nuxt, до гідратації. Vue-застосунок отримує плагін ще до побудови дерева компонентів. Composables, навпаки, запускаються за потребою всередині setup компонентів. Покладеш логіку компонента в плагін і отримаєш зайве навантаження при кожному завантаженні сторінки.
Коли використовувати
- Інтеграція Vue-плагіна (
vue-toastification,pinia,i18n) -> плагін зvueApp.use() - Глобальний API-клієнт доступний скрізь -> плагін з
provide: { api } - Перевикористовувана логіка без Vue-інтеграції -> composable
- Логіка, специфічна для роуту -> middleware
- Браузерний код (аналітика, localStorage) ->
plugin.client.ts - Серверний код (підключення до БД) ->
plugin.server.ts
Як Nuxt завантажує плагіни
Nuxt сканує директорію plugins/ під час збірки й автоматично реєструє кожен файл. При старті плагіни виконуються послідовно в алфавітному порядку. Клієнтські плагіни запускаються після гідратації, серверні виконуються на кожен запит у движку Nitro. Об'єкт provide з кожного плагіна автоматично об'єднується в контекст useNuxtApp() через app.provide(). Саме тому $toast або $api з'являється в useNuxtApp() без жодного явного імпорту в компоненті.
Nuxt 3.10+ також підтримує parallel: true всередині defineNuxtPlugin для плагінів без взаємних залежностей. Це помітно скорочує час старту у великих застосунках.
Типові помилки
1. Немає суфікса .client.ts для браузерного коду
// Неправильно: plugins/analytics.ts
// Виконується і на SSR, і на клієнті = подвійне відстеження, помилки з window
// Правильно: plugins/analytics.client.ts
export default defineNuxtPlugin(() => {
window.analytics.init() // window тут безпечний
})2. Неправильний порядок плагінів при залежностях
// Неправильно: plugins/api.ts завантажується до plugins/auth.ts
// api.ts намагається прочитати auth-токен, якого ще немає
// Правильно: перейменуй на 01.auth.ts та 02.api.ts
// Nuxt сортує за алфавітом, числа мають пріоритетЦе найпоширеніша прихована помилка, яку я бачу в Nuxt-репозиторіях: auth та API завантажуються не в тому порядку, бо ніхто не додав числові префікси, поки щось не зламалось у продакшені.
3. Забутий return { provide }
// Неправильно:
export default defineNuxtPlugin(() => {
const api = { getUser: (id) => $fetch(`/api/users/${id}`) }
// api визначено, але нікуди не передається
})
// Правильно:
export default defineNuxtPlugin(() => {
const api = { getUser: (id) => $fetch(`/api/users/${id}`) }
return { provide: { api } }
})
// Тепер: const { $api } = useNuxtApp() працює в будь-якому компоненті4. Отримання даних безпосередньо в ініціалізації плагіна
Уникай fetch-запитів у коді налаштування плагіна. Вони виконуються поза lifecycle компонентів, тому useAsyncData та useFetch там недоступні. Перенеси отримання даних у composables, де є доступ до правильного контексту запиту.
Де зустрічається
vue-toastification-> глобальні повідомлення в e-commerce застосункахPinia-> налаштування сховищ у SaaS-дашбордах (типово в nuxtjs/starter)Supabase-> auth-клієнт доступний скрізь у CMS і контент-сайтахDay.js-> глобальне форматування дат у блог-платформахSentry-> відстеження помилок, ініціалізоване один раз для всього застосунку
Питання на співбесіді
Q: Як Nuxt визначає порядок виконання плагінів?
A: За алфавітом, за назвою файлу. Числові префікси контролюють порядок: 01.auth.ts виконається до 02.api.ts.
Q: У чому різниця між provide і vueApp.use()?
A: vueApp.use() реєструє Vue-плагін (директиви, компоненти, глобальна логіка install). provide ін'єктує значення в контекст Nuxt, доступне через useNuxtApp(). В одному плагіні часто використовують обидва.
Q: Чи може плагін бути асинхронним?
A: Так. Передай async (nuxtApp) => { ... } у defineNuxtPlugin. Nuxt чекає на асинхронні плагіни перед рендерингом, тому тримай їх швидкими, інакше кожен запит буде чекати.
Q: Як плагіни впливають на гідратацію SSR?
A: Використовуй .client.ts для плагінів, які звертаються до браузерних API. Для спільного стану між сервером і клієнтом використовуй useState() всередині плагіна, а не звичайну змінну.
Q: Що таке parallel: true і коли це використовувати?
A: Додано в Nuxt 3.10. Дозволяє плагіну запускатися паралельно з іншими, без очікування. Використовуй для плагінів без залежностей між ними. Помітно скорочує час старту у великих застосунках.
Приклади
Реєстрація Vue-плагіна
// plugins/toast.client.ts
import Toast from 'vue-toastification'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Toast, { timeout: 3000 })
})
// pages/index.vue
const { $toast } = useNuxtApp()
async function saveUser(data) {
await $fetch('/api/user', { method: 'POST', body: data })
$toast.success('Збережено!')
}Один імпорт, одна реєстрація, доступно на кожній сторінці та в кожному компоненті. Покриває більшість сценаріїв використання плагінів.
Глобальний API-клієнт через provide
// plugins/supabase.ts
import { createClient } from '@supabase/supabase-js'
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
const client = createClient(
config.public.supabaseUrl,
config.public.supabaseKey
)
return {
provide: {
supabase: client
}
}
})
// components/Login.vue
const { $supabase } = useNuxtApp()
async function login(email, password) {
const { data, error } = await $supabase.auth.signInWithPassword({
email,
password
})
if (error) console.error(error.message)
}Supabase-клієнт ініціалізується один раз, повторно використовує пул з'єднань і доступний скрізь без повторного імпорту. Типовий підхід у CMS-стартерах на базі Nuxt.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.