Skip to content

插件

思考🤔:什么是插件?和中间件的区别?

app.use(router).use(pinia).use(ElementPlus).mount('#app')

插件基础知识#

创建插件

Nuxt 推荐将插件放置于 plugins 目录下,例如:

-| plugins/
---| foo.ts // 被扫描
---| bar/
-----| baz.ts // 不被扫描
-----| foz.ts // 不被扫描

Nuxt会自动读取 plugins 目录中的文件,并在创建 Vue 应用程序时加载它们。这意味着该目录下的所有插件,都是自动注册的,无需单独去 nuxt.config.ts 文件中进行配置。

Nuxt 默认只会扫描一层目录。如果希望扫描多层,需要在 nuxt.config.ts 文件中进行配置。

export default defineNuxtConfig({
plugins: ['~/plugins/bar/baz', '~/plugins/bar/foz'],
})

每个插件是一个 ts 文件,会导出 defineNuxtPlugin 方法的调用:

export default defineNuxtPlugin()

defineNuxtPlugin 接收一个回调函数,该回调函数就是插件的主逻辑,回调函数会自动传入 nuxtApp 参数。

export default defineNuxtPlugin((nuxtApp) => {
// 使用nuxtApp做一些操作
})

可以通过环境变量来指定特定的环境下执行插件逻辑:

export default defineNuxtPlugin((nuxtApp) => {
// 指定插件只在客户端执行
if (import.meta.server) return
// 插件逻辑
})

nuxtApp

这是一个运行时上下文对象,提供了许多全局的工具和功能,贯穿于服务端和客户端运行时。官方的文档介绍在 这里。该对象上面有如下的成员:

const nuxtApp = {
vueApp, // 全局的Vue实例,有些时候需要拿到Vue实例从而注册Vue的插件或者自定义指令
versions, // Nuxt以及Vue的版本信息
// These let you call and add runtime NuxtApp hooks
// https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts#L18
hooks,
hook,
callHook,
// 仅在 SSR 期间可用,主要包含一些和服务端相关的上下文信息
ssrContext: {
url,
req,
res,
runtimeConfig,
noSSR,
},
// 服务端向客户端传递的数据载体
payload: {
serverRendered: true, // 是否为服务器渲染
data: {}, // 服务端要向客户端返回的数据
state: {} // 客户端的初始状态
}
// 注册全局功能模块
provide: (name: string, value: any) => void
}
nuxtApp.hook('app:mounted', () => {})

该对象具体对应的属性和方法可以参阅这里

在使用 defineNuxtPlugin 创建插件时,回调函数可以返回一个对象,该对象可以为 nuxtApp 对象提供扩展内容:

export default defineNuxtPlugin(() => {
// 为nuxtApp对象提供扩展内容
return {
provide: {
//...
},
}
})

对象写法

除了回调函数的形式,defineNuxtPlugin 还支持对象写法:

export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre',
async setup(nuxtApp) {},
hooks: {
'app:created'() {
const nuxtApp = useNuxtApp()
},
},
env: {
islands: true,
},
})

加载插件

Nuxt 应用在加载插件的时候,和加载中间件一样,按照 ASCII 码顺序进行加载。如果希望改变加载的顺序,在插件文件前面添加序号即可:

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

加载插件时默认是按照顺序进行加载,将 parallel 设置为 true 可设置为并行加载,Nuxt 不会等到该插件执行结束,而是会直接加载下一个插件。

export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true, // 加载这个插件的时候,是并行加载,不用等到该插件加载结束,直接开始加载下一个插件
async setup(nuxtApp) {
// 下一个插件将立即执行
},
})

使用组合式API以及工具函数

在插件中,可以使用内置的或者自定义的组合式 API 以及工具函数。例如:

composables/useFoo.ts
export const useFoo = () => {
return useState('foo', () => 'bar')
}
plugins/hello.ts
export default defineNuxtPlugin((nuxtApp) => {
const foo = useFoo()
console.log(foo.value)
})

启动应用后,会自动执行该插件代码。

注册Vue插件#

Vue也是支持插件的。如果想要使用 Vue 插件,可以使用 Nuxt 插件来间接的进行注册。先获取到 Vue 的实例

例如,在Vue项目里面,使用 vue-gtag 这个插件来添加 Google Analytics 标签:

import { createApp } from 'vue'
import App from './App.vue'
// 引入
import VueGtag from 'vue-gtag'
const app = createApp(App)
// 注册
app
.use(VueGtag, {
config: { id: 'GA_MEASUREMENT_ID' },
})
.mount('#app')

如果想要在 Nuxt 项目中使用该插件:

import VueGtag, { trackRouter } from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID',
},
})
trackRouter(useRouter())
})

课堂练习

实现一个全局事件总线插件,在不引入状态管理工具(pinia or vuex)的情况下进行组件通信。


-EOF-