plugins (плагины)

В Nuxt есть система плагинов для подключения Vue-плагинов и другого кода при создании приложения.

Nuxt автоматически подхватывает файлы в app/plugins/ и загружает их при создании Vue-приложения.

Все плагины регистрируются автоматически, отдельно в nuxt.config их добавлять не нужно.
Суффикс .server или .client в имени файла загружает плагин только на сервере или только на клиенте.

Регистрация плагинов

Плагинами считаются только файлы на верхнем уровне директории и index-файлы во вложенных папках.

Структура каталогов
-| plugins/
---| foo.ts      // сканируется
---| bar/
-----| baz.ts    // не сканируется
-----| foz.vue   // не сканируется
-----| index.ts  // сканируется (но считается устаревшим)

Регистрируются только foo.ts и bar/index.ts.

Плагины из подпапок можно добавить через опцию app/plugins в nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  plugins: [
    '~/plugins/bar/baz',
    '~/plugins/bar/foz',
  ],
})

Создание плагинов

Единственный аргумент плагина — nuxtApp.

plugins/hello.ts
export default defineNuxtPlugin((nuxtApp) => {
  // Работа с nuxtApp
})

Плагины в виде объекта

Для продвинутых сценариев плагин можно задать объектом:

plugins/hello.ts
export default defineNuxtPlugin({
  name: 'my-plugin',
  enforce: 'pre', // или 'post'
  async setup (nuxtApp) {
    // эквивалент обычного функционального плагина
  },
  hooks: {
    'app:created' () {
      const nuxtApp = useNuxtApp()
      // ...
    },
  },
  env: {
    // false — не запускать при рендере server-only и island-компонентов
    islands: true,
  },
})
При объектном синтаксисе свойства анализируются статически для оптимизации. Не задавайте их в рантайме (например, enforce: import.meta.server ? 'pre' : 'post'). Nuxt предзагружает слушатели хуков при объектном синтаксисе, порядок регистрации плагинов не важен.

Порядок регистрации

Порядок задаётся алфавитной сортировкой имён файлов; для явного порядка используйте числовой префикс:

Структура каталогов
plugins/
 | - 01.myPlugin.ts
 | - 02.myOtherPlugin.ts

В этом примере 02.myOtherPlugin.ts сможет использовать то, что предоставил 01.myPlugin.ts.

Имена сортируются как строки: 10.myPlugin.ts будет перед 2.myOtherPlugin.ts. Поэтому для однозначных номеров используется префикс 0.

Стратегия загрузки

Параллельные плагины

По умолчанию плагины загружаются последовательно. Плагин можно пометить как parallel, тогда следующий плагин начнёт выполняться сразу, не дожидаясь завершения текущего.

plugins/my-plugin.ts
export default defineNuxtPlugin({
  name: 'my-plugin',
  parallel: true,
  async setup (nuxtApp) {
    // следующий плагин запустится сразу
  },
})

Зависимости между плагинами

Если плагин должен ждать другой, укажите его имя в массиве dependsOn:

plugins/depending-on-my-plugin.ts
export default defineNuxtPlugin({
  name: 'depends-on-my-plugin',
  dependsOn: ['my-plugin'],
  async setup (nuxtApp) {
    // этот плагин выполнится после завершения my-plugin
  },
})

Использование композаблов

В плагинах Nuxt можно использовать композаблы и утилиты:

app/plugins/hello.ts
export default defineNuxtPlugin((nuxtApp) => {
  const foo = useFoo()
})

Ограничения:

Если композабл зависит от плагина, регистрируемого позже, он может не сработать. Плагины вызываются по порядку и раньше остального кода.
Если композабл завязан на жизненный цикл Vue, в плагине он не сработает. Композаблы привязаны к экземпляру компонента, а плагины — к экземпляру nuxtApp.

Предоставление хелперов

Чтобы добавить хелпер в экземпляр NuxtApp, верните его из плагина в ключе provide:

export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`,
    },
  }
})

Использование в компонентах:

app/components/Hello.vue
<script setup lang="ts">
const { $hello } = useNuxtApp()
</script>

<template>
  <div>
    {{ $hello('world') }}
  </div>
</template>
Предпочтительнее использовать композаблы, чтобы не засорять глобальное пространство имён и не раздувать основной бандл.
Если плагин предоставляет ref или computed, в <template> они не разворачиваются. Подробнее в документации Vue.

Типизация плагинов

Хелперы, возвращаемые из плагина, типизируются автоматически (в useNuxtApp() и в шаблонах).

Чтобы использовать предоставленный хелпер внутри другого плагина, вызовите useNuxtApp() — тип будет правильным. В общем случае лучше не полагаться на порядок плагинов.

Для сложных случаев типы инъекций можно объявить так:

index.d.ts
declare module '#app' {
  interface NuxtApp {
    $hello (msg: string): string
  }
}

declare module 'vue' {
  interface ComponentCustomProperties {
    $hello (msg: string): string
  }
}

export {}

Vue-плагины

Чтобы подключить Vue-плагин (например, vue-gtag для Google Analytics), создайте Nuxt-плагин:

Установка зависимости:

npm install --save-dev vue-gtag-next

Плагин:

app/plugins/vue-gtag.client.ts
import VueGtag, { trackRouter } from 'vue-gtag-next'

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.use(VueGtag, {
    property: {
      id: 'GA_MEASUREMENT_ID',
    },
  })
  trackRouter(useRouter())
})

Vue-директивы

Кастомную директиву можно зарегистрировать в плагине:

plugins/my-directive.ts
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive('focus', {
    mounted (el) {
      el.focus()
    },
    getSSRProps (binding, vnode) {
      return {}
    },
  })
})
Директиву нужно регистрировать и на клиенте, и на сервере, если только вы не используете её только с одной стороны. Для клиентской директивы можно использовать ~/plugins/my-directive.client.ts и «заглушку» в ~/plugins/my-directive.server.ts.
Узнать больше Кастомные директивы в документации Vue.