plugins

В Nuxt плагины подключают код при создании Vue-приложения: плагины Vue, хуки и другое.

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

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

Зарегистрированные плагины

Только файлы на верхнем уровне директории (или индексные файлы в любых поддиректориях) будут автоматически зарегистрированы как плагины.

Directory structure
-| plugins/
---| foo.ts      // отсканировано
---| bar/
-----| baz.ts    // не сканируется
-----| foz.vue   // не сканируется
-----| index.ts  // в настоящее время сканируется, но устарел

Будут зарегистрированы только foo.ts и bar/index.ts.

Чтобы добавить плагины в поддиректориях, вы можете использовать опцию 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: {
    // Здесь можно зарегистрировать хуки приложения Nuxt на этапе выполнения
    'app:created' () {
      const nuxtApp = useNuxtApp()
      // сделать что-то в хуке
    },
  },
  env: {
    // Установите это значение в `false`, если вы не хотите, чтобы плагин запускался при рендеринге только серверных или island-компонентов.
    islands: true,
  },
})
Если вы используете объектный синтаксис, свойства анализируются статически, чтобы создать более оптимизированную сборку. Поэтому не следует определять их во время рантайма.
Например, установка enforce: import.meta.server ? 'pre' : 'post' приведет к невозможности дальнейшей оптимизации, которую Nuxt сможет выполнить для ваших плагинов. При использовании объектного синтаксиса, Nuxt статически предварительно загружает все слушатели хуков, позволяя вам определять хуки, не заботясь о порядке регистрации плагинов.

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

Вы можете контролировать порядок регистрации плагинов, добавляя к именам файлов префикс с алфавитной нумерацией.

Directory structure
plugins/
 | - 01.myPlugin.ts
 | - 02.myOtherPlugin.ts

В этом примере 02.myOtherPlugin.ts сможет получить доступ ко всему, что было внедрено 01.myPlugin.ts.

Это полезно в ситуациях, когда у вас есть плагин, который зависит от другого плагина.

Если вы новичок в алфавитной нумерации, помните: имена файлов сортируются как строки, а не как числа. Например, 10.myPlugin.ts окажется раньше 2.myOtherPlugin.ts. Поэтому в примере однозначные номера дополняют нулём.

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

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

По умолчанию Nuxt загружает плагины последовательно. Можно пометить плагин как parallel: тогда Nuxt не будет ждать завершения его setup перед запуском следующего плагина.

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 можно использовать композаблы и утилиты:

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

Однако имейте в виду, что существуют некоторые ограничения и различия:

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

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

Чтобы добавить хелпер в NuxtApp, верните его из плагина в поле provide.

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

Затем хелпер можно вызывать в компонентах:

components/Hello.vue
<script setup lang="ts">
// альтернативно, вы также можете использовать его здесь
const { $hello } = useNuxtApp()
</script>

<template>
  <div>
    {{ $hello('world') }}
  </div>
</template>
Надёжнее подключать логику через композаблы, а не через глобальные хелперы: так меньше риск засорить глобальное пространство имён и раздуть точку входа бандла.
Если ваш плагин предоставляет ref или computed, он не будет развернут в <template> компонента.
Это связано с тем, как Vue обрабатывает ref, не лежащие на верхнем уровне шаблона. Подробнее — в документации 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.

Сначала установите зависимость плагина Vue:

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

Затем создайте файл плагина:

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

Аналогичным образом вы можете зарегистрировать в плагине пользовательскую директиву Vue.

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