plugins
Nuxt 提供了一个插件系统,用于在创建 Vue 应用时使用 Vue 插件等功能。
Nuxt 会自动读取 plugins/
目录中的文件,并在创建 Vue 应用时加载它们。
所有插件都会被自动注册,你无需在
nuxt.config
中单独添加它们。你可以在文件名中使用
.server
或 .client
后缀,仅在服务端或客户端加载插件。注册的插件
只有目录顶层的文件(或子目录中的 index 文件)会被自动注册为插件。
Directory structure
-| plugins/
---| foo.ts // 会被扫描
---| bar/
-----| baz.ts // 不会被扫描
-----| foz.vue // 不会被扫描
-----| index.ts // 当前会被扫描,但已废弃
只有 foo.ts
和 bar/index.ts
会被注册。
要添加子目录中的插件,你可以在 nuxt.config.ts
中使用 plugins
选项:
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
}
})
如果使用对象语法,属性会被静态分析以生成更优化的构建。因此,你不应在运行时定义它们。:br
例如,设置
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
之前。这就是示例中对个位数添加 0
前缀的原因。加载策略
并行插件
默认情况下,Nuxt 会按顺序加载插件。你可以将插件定义为 parallel
,这样 Nuxt 不会等待插件执行结束就加载下一个插件。
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` 执行结束后再运行
}
})
使用组合式函数
plugins/hello.ts
export default defineNuxtPlugin((nuxtApp) => {
const foo = useFoo()
})
但需要注意一些限制和差异:
如果组合式函数依赖于稍后注册的插件,它可能无法工作。
插件按顺序依次调用,并且在所有其他内容之前调用。你可能使用的组合式函数依赖于尚未调用的其他插件。
插件按顺序依次调用,并且在所有其他内容之前调用。你可能使用的组合式函数依赖于尚未调用的其他插件。
如果组合式函数依赖于 Vue.js 生命周期,它将无法工作。
通常,Vue.js 组合式函数绑定到当前组件实例,而插件仅绑定到
通常,Vue.js 组合式函数绑定到当前组件实例,而插件仅绑定到
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}!`
}
}
}
})
然后你可以在组件中使用该辅助函数:
components/Hello.vue
<script setup lang="ts">
// 或者,你也可以在这里使用
const { $hello } = useNuxtApp()
</script>
<template>
<div>
{{ $hello('world') }}
</div>
</template>
请注意,我们强烈建议使用组合式函数而不是提供辅助函数,以避免污染全局命名空间并保持主包入口较小。
类型定义插件
如果你从插件返回辅助函数,它们将自动被类型化;你会发现它们在 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 插件依赖:
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
然后创建一个插件文件:
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
中提供一个“存根”指令。::