Nuxt 会自动读取 plugins/ 目录中的文件,并在创建 Vue 应用时加载它们。
nuxt.config 中。.server 或 .client 后缀来指定插件仅在服务端或客户端加载。只有目录顶层的文件(或者任何子目录中的 index 文件)会被自动注册为插件。
-| plugins/
---| foo.ts // 被扫描
---| bar/
-----| baz.ts // 不被扫描
-----| foz.vue // 不被扫描
-----| index.ts // 当前会被扫描,但将被弃用
只有 foo.ts 和 bar/index.ts 会被注册。
要添加子目录中的插件,可以在 nuxt.config.ts 中使用 plugins 选项:
export default defineNuxtConfig({
plugins: [
'~/plugins/bar/baz',
'~/plugins/bar/foz',
],
})
插件唯一传入的参数是 nuxtApp。
export default defineNuxtPlugin((nuxtApp) => {
// Doing something with nuxtApp
})
也可以使用对象语法定义插件,以满足更高级的用例。例如:
export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre', // 或 'post'
async setup (nuxtApp) {
// 这等同于普通的函数式插件
},
hooks: {
// 可以直接在这里注册 Nuxt 应用运行时钩子
'app:created' () {
const nuxtApp = useNuxtApp()
// 在钩子中执行某些操作
},
},
env: {
// 如果你不希望插件在仅服务端渲染或岛屿组件时运行,将该值设置为 `false`。
islands: true,
},
})
enforce: import.meta.server ? 'pre' : 'post' 会阻碍 Nuxt 对你的插件进行未来优化。
使用对象语法时,Nuxt 会静态预加载任何钩子监听器,允许你定义钩子而无需担心插件注册顺序。你可以通过在文件名前添加“字母数字”编号来控制插件的注册顺序。
plugins/
| - 01.myPlugin.ts
| - 02.myOtherPlugin.ts
在这个例子中,02.myOtherPlugin.ts 能访问 01.myPlugin.ts 注入的任何内容。
这在某个插件依赖另一个插件时非常有用。
10.myPlugin.ts 会排在 2.myOtherPlugin.ts 之前。这就是示例中对个位数字前加零的原因。默认情况下,Nuxt 顺序加载插件。你可以将插件定义为 parallel,使 Nuxt 不必等到该插件执行完毕就开始加载下一个插件。
export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true,
async setup (nuxtApp) {
// the next plugin will be executed immediately
},
})
如果一个插件需要等待另一个插件完成才能运行,你可以在 dependsOn 数组中添加它所依赖插件的名称。
export default defineNuxtPlugin({
name: 'depends-on-my-plugin',
dependsOn: ['my-plugin'],
async setup (nuxtApp) {
// this plugin will wait for the end of `my-plugin`'s execution before it runs
},
})
export default defineNuxtPlugin((nuxtApp) => {
const foo = useFoo()
})
但需要注意一些限制和区别:
nuxtApp 实例。如果你想在 NuxtApp 实例上提供帮助函数,可以从插件中通过 provide 属性返回。
export default defineNuxtPlugin(() => {
return {
provide: {
hello: (msg: string) => `Hello ${msg}!`,
},
}
})
export default defineNuxtPlugin({
name: 'hello',
setup () {
return {
provide: {
hello: (msg: string) => `Hello ${msg}!`,
},
}
},
})
然后你可以在组件中使用该帮助函数:
<script setup lang="ts">
// 另外,你也可以在这里使用
const { $hello } = useNuxtApp()
</script>
<template>
<div>
{{ $hello('world') }}
</div>
</template>
composables 替代直接提供帮助函数,以避免污染全局命名空间并保持主包体积尽可能小。如果你从插件返回帮助函数,它们会自动被类型化;你可以在 useNuxtApp() 返回值和模板内获得它们的类型支持。
useNuxtApp() 获取具备类型的版本。但一般情况下除非确保插件加载顺序,否则应避免这样做。对于高级用例,你可以声明注入属性的类型:
declare module '#app' {
interface NuxtApp {
$hello (msg: string): string
}
}
declare module 'vue' {
interface ComponentCustomProperties {
$hello (msg: string): string
}
}
export {}
如果你想使用 Vue 插件,比如通过 vue-gtag 添加 Google Analytics 标签,可以使用 Nuxt 插件来实现。
首先,安装 Vue 插件依赖:
npm install --save-dev vue-gtag-next
yarn add --dev vue-gtag-next
pnpm add -D vue-gtag-next
bun add -D vue-gtag-next
然后创建一个插件文件:
import VueGtag, { trackRouter } from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID',
},
})
trackRouter(useRouter())
})
同样,你可以在插件中注册自定义 Vue 指令。
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('focus', {
mounted (el) {
el.focus()
},
getSSRProps (binding, vnode) {
// 你可以在这里提供 SSR 特定的属性
return {}
},
})
})
~/plugins/my-directive.client.ts,并在 ~/plugins/my-directive.server.ts 提供一个“空”指令。