Nuxt3 中文课程 《实战全栈开发简书》.

plugins

Nuxt拥有一个插件系统,可以在创建Vue应用程序时使用Vue插件和其他功能。

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

这里面的所有插件都会自动注册,你不需要单独将它们添加到你的nuxt.config中。
你可以在文件名中使用.server.client后缀,只在服务器端或客户端上加载插件。

注册的插件

只有目录的顶层文件(或任何子目录中的索引文件)才会自动注册为插件。

目录���构
-| plugins/
---| foo.ts      // 被扫描
---| bar/
-----| baz.ts    // 不被扫描
-----| foz.vue   // 不被扫描
-----| index.ts  // 目前被扫描,但已弃用

只有foo.tsbar/index.ts会被注册。

要在子目录中添加插件,你可以在nuxt.config.tsplugins选项中使用:

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`。
    islands: true
  }
})
如果使用对象语法,则属性可能会在将来进行静态分析,以生成更优化的构建。因此,不应在运行时定义它们。
例如,设置enforce: process.server ? 'pre' : 'post'将破坏Nuxt为插件执行的任何未来优化。

注册顺序

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

目录结构
plugins/
 | - 01.myPlugin.ts
 | - 02.myOtherPlugin.ts

在这个例子中,02.myOtherPlugin.ts可以访问01.myPlugin.ts注入的任何内容。

这在一个插件依赖于另一个插件的情况下非常有用。

如果你对“字母”编号不熟悉,请记住文件名按字符串排序,而不是按数值排序。例如,10.myPlugin.ts会排在2.myOtherPlugin.ts之前。这就是为什么示例中将一位数前缀添加了0

加载策略

默认情况下,Nuxt按顺序加载插件。你可以将插件定义为parallel,这样Nuxt在加载下一个插件之前不会等待插件执行结束。

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

使用组合式 API

在Nuxt插件中,你可以使用组合式 API以及工具函数

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

但是,请记住存在一些限制和差异:

如果一个组合式依赖于稍后注册的另一个插件,可能无法正常工作。
插件按顺序顺序调用,并且在其他所有内容之前调用。你可能会使用一个依赖于尚未被调用的其他插件的组合式。
如果一个组合式依赖于Vue.js的生命周期,它将无法正常工作。
通常,Vue.js组合式与当前组件实例绑定,而插件仅与nuxtApp实例绑定。

提供辅助函数

如果你想要在NuxtApp实例上提供一个辅助函数,请在插件中使用provide键返回它。

plugins/hello.ts
export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `你好${msg}`
    }
  }
})

然后你可以在组件中使用这个辅助函数:

components/Hello.vue
<script setup lang="ts">
// 或者,你也可以在这里使用它
const { $hello } = useNuxtApp()
</script>

<template>
  <div>
    {{ $hello('世界') }}
  </div>
</template>
请注意,我们强烈建议使用组合式 API代替提供辅助函数,以避免污染全局命名空间并保持入口文件的大小。

插件类型

如果从插件返回辅助函数,它们将自动获得类型;你可以在useNuxtApp()的返回值和模板中找到它们的类型。

如果需要在另一个插件中使用提供的辅助函数,可以调用useNuxtApp()来获取类型化版本。但是,一般情况下,除非你确定插件的顺序,否则应避免这样做。

对于高级用例,可以这样声明注入属性的类型:

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

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

export {}
如果使用WebStorm,你可能需要增强@vue/runtime-core,直到解决此问题

Vue插件

如果你想要使用Vue插件,比如vue-gtag来添加Google Analytics标签,你可以使用Nuxt插件来实现。

首先,安装Vue插件的依赖:

yarn add --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特定的props
      return {}
    }
  })
})
如果你注册了一个Vue指令,你必须在客户端和服务器端都注册它,除非你只在一个端口渲染时使用它。如果这个指令只在客户端有意义,你可以将它移动到~/plugins/my-directive.client.ts,并在~/plugins/my-directive.server.ts中为服务器端提供一个'存根'指令。
Read more in Vue文档上的自定义指令.