---
title: "plugins"
description: "Nuxt 有一个插件系统，可以在创建 Vue 应用时使用 Vue 插件及更多功能。"
canonical_url: "https://nuxt.zhcndoc.com/docs/3.x/directory-structure/plugins"
---
# plugins

> Nuxt 有一个插件系统，可以在创建 Vue 应用时使用 Vue 插件及更多功能。

Nuxt 会自动读取 `plugins/` 目录中的文件，并在创建 Vue 应用时加载它们。

::note
目录内的所有插件都会自动注册，无需单独将它们添加到你的 `nuxt.config` 中。
::

::note
你可以在文件名中使用 `.server` 或 `.client` 后缀来指定插件仅在服务端或客户端加载。
::

## 已注册插件

只有目录顶层的文件（或者任何子目录中的 `index` 文件）会被自动注册为插件。

```bash [目录结构]
-| plugins/
---| foo.ts      // 被扫描
---| bar/
-----| baz.ts    // 不被扫描
-----| foz.vue   // 不被扫描
-----| index.ts  // 当前会被扫描，但将被弃用
```

只有 `foo.ts` 和 `bar/index.ts` 会被注册。

要在子目录中添加插件，你可以在 `nuxt.config.ts` 中使用 [`plugins`](https://nuxt.zhcndoc.com/docs/3.x/api/nuxt-config#plugins-1) 选项：

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

## 创建插件

传递给插件的唯一参数是 [`nuxtApp`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-nuxt-app)。

```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin((nuxtApp) => {
  // 使用 nuxtApp 做一些事情
})
```

### 对象语法插件

也可以使用对象语法定义插件，以满足更高级的用例。例如：

```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin({
  name: 'my-plugin',
  enforce: 'pre', // 或 'post'
  async setup (nuxtApp) {
    // 这等同于普通的函数式插件
  },
  hooks: {
    // 可以直接在这里注册 Nuxt 应用运行时钩子
    'app:created' () {
      const nuxtApp = useNuxtApp()
      // 在钩子中执行某些操作
    },
  },
  env: {
    // 如果你不希望插件在仅服务端渲染或岛屿组件时运行，将该值设置为 `false`。
    islands: true,
  },
})
```

::video-accordion{title="观看 Alexander Lichter 关于 Nuxt 插件对象语法的视频" videoId="2aXZyXB1QGQ"}
::

::note
如果使用对象语法，属性会被静态分析以生成更优化的构建，因此不应在运行时定义它们。 :br
例如，设置 `enforce: import.meta.server ? 'pre' : 'post'` 会阻碍 Nuxt 对你的插件进行未来优化。
使用对象语法时，Nuxt 会静态预加载任何钩子监听器，允许你定义钩子而无需担心插件注册顺序。
::

## 注册顺序

你可以通过在文件名前添加“字母数字”编号来控制插件的注册顺序。

```bash [目录结构]
plugins/
 | - 01.myPlugin.ts
 | - 02.myOtherPlugin.ts
```

在这个例子中，`02.myOtherPlugin.ts` 能访问 `01.myPlugin.ts` 注入的任何内容。

这在某个插件依赖另一个插件时非常有用。

::note
如果你刚接触“字母数字”编号，请记住文件名是按字符串排序的，而非数字值。例如，`10.myPlugin.ts` 会排在 `2.myOtherPlugin.ts` 之前。这就是示例中对个位数字前加零的原因。
::

## 加载策略

### 并行插件

默认情况下，Nuxt 顺序加载插件。你可以将插件定义为 `parallel`，使 Nuxt 不必等到该插件执行完毕就开始加载下一个插件。

```ts twoslash [plugins/my-plugin.ts]
export default defineNuxtPlugin({
  name: 'my-plugin',
  parallel: true,
  async setup (nuxtApp) {
    // 下一个插件会立即执行
  },
})
```

### 有依赖的插件

如果一个插件需要等待另一个插件完成才能运行，你可以在 `dependsOn` 数组中添加它所依赖插件的名称。

```ts twoslash [plugins/depending-on-my-plugin.ts]
export default defineNuxtPlugin({
  name: 'depends-on-my-plugin',
  dependsOn: ['my-plugin'],
  async setup (nuxtApp) {
    // 该插件会等待 `my-plugin` 执行结束后才运行
  },
})
```

## 使用组合式函数

你可以在 Nuxt 插件中使用[组合式函数](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/composables)和 [utils](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/utils)：

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

但需要注意一些限制和区别：

::important
**如果一个组合式函数依赖于之后注册的插件，可能无法正常工作。** :br 

插件会按顺序调用且早于其它操作，你可能会使用一个依赖尚未调用插件的组合式函数。
::

::important
**如果组合式函数依赖 Vue.js 生命周期，它将无法工作。** :br 

通常，Vue.js 组合式函数会绑定到当前组件实例，而插件只会绑定到 [`nuxtApp`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-nuxt-app) 实例。
::

## 提供帮助函数

如果你想在 [`NuxtApp`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-nuxt-app) 实例上提供帮助函数，可以在插件中通过 `provide` 键返回它。

::code-group
```ts twoslash [plugins/hello.ts]
export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`,
    },
  }
})
```

```ts twoslash [plugins/hello-object-syntax.ts]
export default defineNuxtPlugin({
  name: 'hello',
  setup () {
    return {
      provide: {
        hello: (msg: string) => `Hello ${msg}!`,
      },
    }
  },
})
```
::

然后你可以在组件中使用该帮助函数：

```vue [components/Hello.vue]
<script setup lang="ts">
// 另外，你也可以在这里使用
const { $hello } = useNuxtApp()
</script>

<template>
  <div>
    {{ $hello('world') }}
  </div>
</template>
```

::important
请注意，我们强烈建议使用[组合式函数](https://nuxt.zhcndoc.com/docs/3.x/directory-structure/composables)，而不是提供帮助函数，以避免污染全局命名空间，并保持主 bundle 入口精简。
::

::warning
**如果你的插件提供了 `ref` 或 `computed`，它们在组件 `<template>` 中不会被解包。** :br
这是由于 Vue 处理非模板顶层 ref 的方式造成的。你可以在 [Vue 文档](https://vue.zhcndoc.com/guide/essentials/reactivity-fundamentals.html#caveat-when-unwrapping-in-templates) 了解更多。
::

## 插件类型定义

如果你从插件返回帮助函数，它们会自动被类型化；你可以在 `useNuxtApp()` 返回值和模板内获得它们的类型支持。

::note
如果你需要在另一个插件中使用已提供的帮助函数，可以调用 [`useNuxtApp()`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-nuxt-app) 来获取带类型的版本。但通常应避免这样做，除非你确定插件的顺序。
::

对于高级用例，你可以声明注入属性的类型：

```ts [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](https://github.com/MatteoGabriele/vue-gtag) 添加 Google Analytics 标签，可以使用 Nuxt 插件来实现。

首先，安装 Vue 插件依赖：

::code-group{sync="pm"}
```bash [npm]
npm install --save-dev vue-gtag-next
```

```bash [yarn]
yarn add --dev vue-gtag-next
```

```bash [pnpm]
pnpm add -D vue-gtag-next
```

```bash [bun]
bun add -D vue-gtag-next
```

```bash [deno]
deno add -D npm:vue-gtag-next
```
::

然后创建一个插件文件：

```ts [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 指令。

```ts twoslash [plugins/my-directive.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.vueApp.directive('focus', {
    mounted (el) {
      el.focus()
    },
    getSSRProps (binding, vnode) {
      // 你可以在这里提供 SSR 特定的属性
      return {}
    },
  })
})
```

::warning
如果你注册 Vue 指令，**必须**在客户端和服务端都注册，除非你只在某一端渲染时使用它。如果指令仅在客户端有意义，可以将其移动到 `~/plugins/my-directive.client.ts`，并在 `~/plugins/my-directive.server.ts` 提供一个“空”指令。
::

::read-more
```yaml [props]
icon: i-simple-icons-vuedotjs
title: Vue 文档上的自定义指令
to: https://vue.zhcndoc.com/guide/reusability/custom-directives.html
target: _blank
```
::


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
