plugins

Nuxt 擁有一個外掛系統,用於在建立 Vue 應用程式時使用 Vue 外掛及其他功能。

Nuxt 會自動讀取 app/plugins/ 目錄中的檔案,並在建立 Vue 應用程式時載入它們。

所有外掛都會自動註冊,您無需將它們單獨新增到 nuxt.config 中。
您可以在檔名稱中使用 .server.client 字尾,以便僅在伺服器端或客戶端載入外掛。

已註冊的外掛

只有目錄頂層的檔案(或任何子目錄中的索引檔案)才會被自動註冊為外掛。

目錄結構
-| plugins/
---| foo.ts      // scanned
---| bar/
-----| baz.ts    // not scanned
-----| foz.vue   // not scanned
-----| index.ts  // currently scanned but deprecated

只有 foo.tsbar/index.ts 會被註冊。

要在子目錄中新增外掛,您可以使用 nuxt.config.ts 中的 app/plugins 選項

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

建立外掛

傳遞給外掛的唯一引數是 nuxtApp

plugins/hello.ts
export default defineNuxtPlugin((nuxtApp) => {
  // Doing something with nuxtApp
})

物件語法外掛

也可以使用物件語法定義外掛,以實現更高階的用例。例如

plugins/hello.ts
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,
  },
})
如果您使用物件語法,屬性將進行靜態分析以生成更最佳化的構建。因此,您不應在執行時定義它們。
例如,設定 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 之前。這就是為什麼示例中個位數數字前面加上 0 的原因。

載入策略

並行外掛

預設情況下,Nuxt 按順序載入外掛。您可以將外掛定義為 parallel,這樣 Nuxt 就不會等到外掛執行結束才載入下一個外掛。

plugins/my-plugin.ts
export default defineNuxtPlugin({
  name: 'my-plugin',
  parallel: true,
  async setup (nuxtApp) {
    // the next plugin will be executed immediately
  },
})

帶依賴的外掛

如果一個外掛需要在另一個外掛執行之前等待,您可以將該外掛的名稱新增到 dependsOn 陣列中。

plugins/depending-on-my-plugin.ts
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
  },
})

使用組合式函式

您可以在 Nuxt 外掛中使用 組合式函式 以及 工具函式

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

但是,請記住有一些限制和差異

如果組合式函式依賴於稍後註冊的另一個外掛,它可能無法工作。
外掛按順序且在所有其他內容之前呼叫。您可能正在使用一個依賴於尚未呼叫的另一個外掛的組合式函式。
如果組合式函式依賴於 Vue.js 生命週期,它將無法工作。
通常,Vue.js 組合式函式繫結到當前元件例項,而外掛僅繫結到 nuxtApp 例項。

提供輔助函式

如果您想在 NuxtApp 例項上提供輔助函式,請在 provide 鍵下從外掛返回它。

export default defineNuxtPlugin(() => {
  return {
    provide: {
      hello: (msg: string) => `Hello ${msg}!`,
    },
  }
})

然後您可以在元件中使用該輔助函式

app/components/Hello.vue
<script setup lang="ts">
// alternatively, you can also use it here
const { $hello } = useNuxtApp()
</script>

<template>
  <div>
    {{ $hello('world') }}
  </div>
</template>
請注意,我們強烈建議使用 組合式函式 而不是提供輔助函式,以避免汙染全域性名稱空間並保持主捆綁入口檔案小巧。
如果您的外掛提供了 refcomputed,它不會在元件 <template> 中解包。
這是由於 Vue 處理非模板頂層引用(refs)的方式所致。您可以在Vue 文件中.

瞭解更多資訊。

型別化外掛

如果您從外掛中返回輔助函式,它們將自動進行型別化;您會發現它們在 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

然後建立一個外掛檔案

app/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) {
      // you can provide SSR-specific props here
      return {}
    },
  })
})
如果您註冊 Vue 指令,則必須在客戶端和伺服器端都註冊它,除非您只在渲染其中一方時使用它。如果指令僅在客戶端有意義,您始終可以將其移動到 ~/plugins/my-directive.client.ts,並在 ~/plugins/my-directive.server.ts 中為伺服器提供一個“存根”指令。
Vue 文件中的自定義指令 中閱讀更多內容。