plugins
Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application.
Nuxt automatically reads the files in the plugins/
directory and loads them at the creation of the Vue application.
nuxt.config
separately..server
or .client
suffix in the file name to load a plugin only on the server or client side.Registered Plugins
Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins.
-| plugins/
---| foo.ts // scanned
---| bar/
-----| baz.ts // not scanned
-----| foz.vue // not scanned
-----| index.ts // currently scanned but deprecated
Only foo.ts
and bar/index.ts
would be registered.
To add plugins in subdirectories, you can use the plugins
option in nuxt.config.ts
:
export default defineNuxtConfig({
plugins: [
'~/plugins/bar/baz',
'~/plugins/bar/foz'
]
})
Creating Plugins
The only argument passed to a plugin is nuxtApp
.
export default defineNuxtPlugin(nuxtApp => {
// Doing something with nuxtApp
})
Object Syntax Plugins
It is also possible to define a plugin using an object syntax, for more advanced use cases. For example:
export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre', // or 'post'
async setup (nuxtApp) {
// this is the equivalent of a normal functional plugin
},
hooks: {
// You can directly register Nuxt app runtime hooks here
'app:created'() {
const nuxtApp = useNuxtApp()
// do something in the hook
}
},
env: {
// Set this value to `false` if you don't want the plugin to run when rendering server-only or island components.
islands: true
}
})
For example, setting
enforce: import.meta.server ? 'pre' : 'post'
would defeat any future optimization Nuxt is able to do for your plugins.
Nuxt does statically pre-load any hook listeners when using object-syntax, allowing you to define hooks without needing to worry about order of plugin registration.Registration Order
You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names.
plugins/
| - 01.myPlugin.ts
| - 02.myOtherPlugin.ts
In this example, 02.myOtherPlugin.ts
will be able to access anything that was injected by 01.myPlugin.ts
.
This is useful in situations where you have a plugin that depends on another plugin.
10.myPlugin.ts
would come before 2.myOtherPlugin.ts
. This is why the example prefixes single digit numbers with 0
.Loading Strategy
Parallel Plugins
By default, Nuxt loads plugins sequentially. You can define a plugin as parallel
so Nuxt won't wait the end of the plugin's execution before loading the next plugin.
export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true,
async setup (nuxtApp) {
// the next plugin will be executed immediately
}
})
Plugins With Dependencies
If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the dependsOn
array.
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
}
})
Using Composables
You can use composables as well as utils within Nuxt plugins:
export default defineNuxtPlugin((nuxtApp) => {
const foo = useFoo()
})
However, keep in mind there are some limitations and differences:
Plugins are called in order sequentially and before everything else. You might use a composable that depends on another plugin which has not been called yet.
Normally, Vue.js composables are bound to the current component instance while plugins are only bound to
nuxtApp
instance.Providing Helpers
If you would like to provide a helper on the NuxtApp
instance, return it from the plugin under a provide
key.
export default defineNuxtPlugin(() => {
return {
provide: {
hello: (msg: string) => `Hello ${msg}!`
}
}
})
You can then use the helper in your components:
<script setup lang="ts">
// alternatively, you can also use it here
const { $hello } = useNuxtApp()
</script>
<template>
<div>
{{ $hello('world') }}
</div>
</template>
composables
instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small.ref
or computed
, it will not be unwrapped in a component <template>
.This is due to how Vue works with refs that aren't top-level to the template. You can read more about it in the Vue documentation.
Typing Plugins
If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of useNuxtApp()
and within your templates.
useNuxtApp()
to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order.For advanced use-cases, you can declare the type of injected properties like this:
declare module '#app' {
interface NuxtApp {
$hello (msg: string): string
}
}
declare module 'vue' {
interface ComponentCustomProperties {
$hello (msg: string): string
}
}
export {}
@vue/runtime-core
until this issue is resolved.Vue Plugins
If you want to use Vue plugins, like vue-gtag to add Google Analytics tags, you can use a Nuxt plugin to do so.
First, install the Vue plugin dependency:
yarn add --dev vue-gtag-next
Then create a plugin file:
import VueGtag, { trackRouter } from 'vue-gtag-next'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueGtag, {
property: {
id: 'GA_MEASUREMENT_ID'
}
})
trackRouter(useRouter())
})
Vue Directives
Similarly, you can register a custom Vue directive in a plugin.
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.directive('focus', {
mounted (el) {
el.focus()
},
getSSRProps (binding, vnode) {
// you can provide SSR-specific props here
return {}
}
})
})
~/plugins/my-directive.client.ts
and provide a 'stub' directive for the server in ~/plugins/my-directive.server.ts
.