為了不重複造輪子,在專案中導入現成的套件是常見的做法,但若這個套件在 Nuxt 3 沒有專用的模組或插件,再導入的過程中可能會遇到一些問題,多數情況我們可以使用 Nuxt 3 提供的插件目錄 (Plugins Directory) 來建立插件,為的就是將這些第三方套件安裝至 Nuxt 中使用。
我們導入套件,首先也會觀察套件的支援性,如果預計導入的套件原本就支援 Vue 3,那麼導入至 Nuxt 3 基本上蠻容易的,反之,你可能就需要依據套件的官方文件來決定在哪個生命週期階段來初始化等。
在 Vue 3 導入套件的流程,只要套件封裝的好,基本都是如下步驟,這種步驟的套件,基本上在 Nuxt 3 可以依照這個步驟就能使用。
比較會遇到問題的,多數是需要先在 Vue 的實體 (Instance) 中初始化套件元件或方法,來提供全域的元件與 Helper,例如在 Vue 的 main.js 中初始化套件來設定全域元件或全域的 Helper。
// 設定全域元件 Vue3CustomComponent
app.component('Vue3CustomComponent', Vue3CustomComponent)
// 設定全域自定義指令
app.directive(Vue3CustomComponent)
// 安裝插件
app.use('my-directive', Vue3CustomDirective)
// 設定全域 Helper,名為 $customFunction
app.config.globalProperties.$customFunction = Vue3CustomFunction
// 或以 provide 的方式來提供全域的數值或函式
app.provide('customValue', 'hello')
在 Vue 3 中使用的套件,如果遇到需要使用 Vue 實體來進行安裝的話,我們就需要能夠得到上程式碼中的 app
這個 Vue 的實體。
在 Nuxt 3 中想要得到 Vue 的實體,你需要使用內建的組合式函式 useNuxtApp
先得到 Nuxt 的上下文,以訪問 Vue 的實體。
const nuxtApp = useNuxtApp()
const vueApp = nuxtApp.vueApp
有了 Vue 的實體 vueApp
後,你就可以像在 Vue 中初始化套件的方式來依樣畫葫蘆,而提供全域 Helper 的方法,可以使用 nuxtApp.provider()
來共享給整個 Nuxt。
Vue3-Toastify 是一個支援 Vue 3 的套件,讓你可以很方便的來為網頁添加通知 (Notifications)。
依據官網的文件,在 Vue 3 安裝完套件後,如果想要在全域呼叫建立通知的函式,需要使用 Vue 實體來安裝。
// Vue 3 專案的 main.js
import Vue3Toastify from 'vue3-toastify'
app.use(Vue3Toastify, {
autoClose: 3000,
});
在需要使用 Vue3-Toastify 的地方,載入 toast
與相關樣式。
<script setup>
import { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
</script>
就可以呼叫 toast
來產生通知囉。
<script setup>
toast.success('就是這麼簡單!')
</script>
通常我們在導入套件或有需求來操作 Vue 的實體,如同我們現在要在 Nuxt 導入 Vue3-Toastify,可以透過建立 Nuxt 插件的方式來進行導入。
安裝套件
npm install -D vue3-toastify
建立插件 ./plugins/vue3-toastify.js 檔案內容如下:
import Vue3Toastify from 'vue3-toastify'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Vue3Toastify, { autoClose: 1000 })
})
在 defineNuxtPlugin 插件函式實作中,會得到的唯一參數 nuxtApp
,這個 nuxtApp
就是 Nuxt 的實體,我們可以透過它來存取 vueApp
來做安裝Vue3Toastify
的動作,如下程式碼,我們也傳入了一個選項 autoClose: 1000,作為全域的預設值。
nuxtApp.vueApp.use(Vue3Toastify, { autoClose: 1000 })
最後在需要使用通知的頁面,導入通知函式與樣式,就可以使用囉。
<template>
<div>
<button @click="notify">建立通知</button>
</div>
</template>
<script setup>
import { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
const notify = () => {
toast("就是這麼簡單!")
}
</script>
我們也可以透過 Nuxt 插件直接全域載入 Vue3-Toastify 的樣式與建立全域的 toast
函式 。
修改插件 ./plugins/vue3-toastify.js 檔案內容如下:
import Vue3Toastify, { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(Vue3Toastify, { autoClose: 1000 })
return {
provide: { toast },
}
})
當 Nuxt 啟動後,這個插件將會被自動載入,並載入 Vue3Toastify
樣式與安裝,並在 defineNuxtPlugin 的回傳的物件屬性 provide
添加 toast
函式,這個 Vue3-Toastify 建立通知的函式 toast
,就會以全域的 Helper 來供 Nuxt 專案使用。
全域的 Helper 的呼叫,會在名稱上加上 $
符號,如下程式碼,我們在頁面中就可以直接呼叫這個 $toast
來做使用囉。
<template>
<div>
<button @click="notify">建立通知</button>
</div>
</template>
<script setup>
const notify = () => {
useNuxtApp().$toast("就是這麼簡單!")
}
</script>
舉例我們插件資料夾有下列插件。
plugin
├── myClientOnlyPlugin.client.js
├── myOtherPlugin.js
└── myPlugin.js
插件註冊執行的順序如下:
如果你想要自訂插件的註冊順序,你可以為插件的檔案名稱加上數字或字母字串來編號,預設情況插件的註冊順序,是依據字母的順序來 (alphabetical) 註冊。
middleware
├── 01.myPlugin.js
├── 02.myOtherPlugin.js
└── 03.myClientOnlyPlugin.client.js
這邊要注意的是,排序是依據字串,而不是數值,所以 10.new.js 是會出現在 2.new.js 之前,這也就是為什麼上面的例子檔名要加上前綴 0
。
預設的情況下,Nuxt 3 是依據插件檔案的字母順序來逐一開始載入插件,如果你希望插件可以同時間載入,你可以在插件的實作以物件的方式來定義,並設置 parallel
選項為 true
,這樣 Nuxt 就會在載入這個插件時,不等待至載入結束,而是與下一個插件同時載入。
export default defineNuxtPlugin({
name: 'my-plugin',
parallel: true, // true 表示下一個插件立刻開始載入,否則得等待這個插件載入完畢
async setup (nuxtApp) {
// ...
}
})
基本上導入第三方套件只要 Vue 3 能夠支援,基本上都能夠導入 ,筆者也建議多以 Vue 3 支援的套件為首要考量,至於套件可能需要存取 windows 或瀏覽器 API 等,你也可以透過插件檔案的副檔名 .client 或 .server 來控制在客戶端或伺服器端執行,而其他不依賴前端 Vue 實體等後端插件,會遇到的狀況就相對較少,本篇也將著重在建立可能需要前端 Vue 實體的插件來導入 Vue 3 的套件至 Nuxt 3 中。
感謝大家的閱讀,歡迎大家給予建議與討論,也請各位大大鞭小力一些:)
如果對這個 Nuxt 3 系列感興趣,可以訂閱
接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。
參考資料