Skip to main content

Що таке 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) контролюють порядок

Швидкий приклад

javascript
// 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 для браузерного коду

javascript
// Неправильно: plugins/analytics.ts // Виконується і на SSR, і на клієнті = подвійне відстеження, помилки з window // Правильно: plugins/analytics.client.ts export default defineNuxtPlugin(() => { window.analytics.init() // window тут безпечний })

2. Неправильний порядок плагінів при залежностях

javascript
// Неправильно: plugins/api.ts завантажується до plugins/auth.ts // api.ts намагається прочитати auth-токен, якого ще немає // Правильно: перейменуй на 01.auth.ts та 02.api.ts // Nuxt сортує за алфавітом, числа мають пріоритет

Це найпоширеніша прихована помилка, яку я бачу в Nuxt-репозиторіях: auth та API завантажуються не в тому порядку, бо ніхто не додав числові префікси, поки щось не зламалось у продакшені.

3. Забутий return { provide }

javascript
// Неправильно: 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-плагіна

javascript
// 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

javascript
// 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.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?