Nuxt 團隊與 Google 的 Chrome Aurora 團隊合作,很高興宣布公開測試版 Nuxt Scripts 的發佈。
Nuxt Scripts 是一種更好的第三方腳本處理方式,可提供更好的效能、隱私、安全性及開發者體驗。
開始使用 Nuxt Scripts
一年多前,Daniel 發佈了最初的 Nuxt Scripts RFC。該 RFC 提出了一個模組,該模組將「允許管理和最佳化第三方腳本,遵循高效能和合規網站的最佳實踐」。
在解決第三方腳本相關的效能問題方面,我擁有 個人經驗,我知道這些效能最佳化有多困難。儘管如此,我仍然渴望解決這個問題並接管該專案。
以 RFC 作為想法的種子,我開始使用 Unhead 原型設計它的 外觀。
思考我究竟想建構什麼時,我發現真正的問題不僅僅是如何載入「最佳化」的第三方腳本,而是如何讓使用第三方腳本的整體體驗更好。
為什麼要建構第三方腳本模組?
94% 的網站至少使用一個第三方供應商,平均網站有 五個第三方供應商。
我們知道第三方腳本並不完美;它們會 減慢網路速度、造成隱私和安全性問題,而且很難使用。
然而,它們基本上很有用,而且不會很快消失。
透過探討第三方腳本的問題,我們可以了解哪些地方可以改進。
😒 開發者體驗:全堆疊頭痛
讓我們逐步了解如何使用一個虛構的 tracker.js
腳本將第三方腳本新增到您的 Nuxt 應用程式,該腳本會將 track
函數新增到視窗中。
我們首先使用 useHead
載入腳本。
useHead({ scripts: [{ src: '/tracker.js', defer: true }] })
但是,現在讓我們嘗試讓腳本功能在我們的應用程式中運作。
以下是在 Nuxt 中使用第三方腳本時的常見步驟
- 所有內容都必須為了 SSR 安全性而包裝。
- 對於腳本是否已載入的不可靠檢查。
- 擴充視窗物件以取得類型。
<script setup>
// ❌ Oops, window is not defined!
// 💡 The window can't be directly accessed if we use SSR in Nuxt.
// 👉 We need to make this SSR safe
window.track('page_view', useRoute().path)
</script>
🐌 效能:「為什麼我無法在 Lighthouse 上獲得 100 分?」
為了讓訪客開始與您的 Nuxt 網站互動,需要下載應用程式套件,並且 Vue 需要將應用程式執行個體水合化。
即使使用 async
或 defer
,載入第三方腳本也會干擾此水合化過程。這會減慢網路速度並阻礙主執行緒,導致使用者體驗下降和 Core Web Vitals 分數不佳。
Chrome 使用者體驗報告顯示,具有大量第三方資源的 Nuxt 網站通常具有較差的 與下一個繪圖互動 (INP) 和 最大內容繪製 (LCP) 分數。
若要了解第三方腳本如何降低效能,我們可以查看 Web Almanac 2022。該報告顯示,前 10 大第三方腳本的平均中位數阻擋時間為 1.4 秒。
🛡️ 隱私與安全性:別作惡?
在前 10,000 個網站中,有 58% 的網站的第三方腳本會交換儲存在外部 Cookie 中的追蹤 ID,這表示即使停用第三方 Cookie,它們也可以跨網站追蹤使用者。
雖然在許多情況下,我們與使用的供應商之間的關係是固定的,但我們應該盡可能減少洩漏終端使用者資料的數量。
當我們承擔隱私影響時,就很難在我們的隱私權政策中準確傳達這些影響,並建構符合 GDPR 等法規的同意管理。
使用第三方腳本時的安全性也是一個問題。第三方腳本是惡意行為者常用的攻擊媒介,大多數腳本沒有為其腳本提供 integrity
雜湊,這表示它們可能會隨時遭到入侵並將惡意程式碼注入您的應用程式。
Nuxt Scripts 如何解決這些問題?
可組合:useScript
此可組合函式位於 <script>
標籤和新增至 window.{thirdPartyKey}
的功能之間。
對於 <script>
標籤,可組合函式
- 可以完全掌握腳本的載入和錯誤狀態
- 預設情況下,當 Nuxt 將應用程式水合化時載入腳本,以獲得稍微更好的效能。
- 限制
crossorigin
和referrerpolicy
以改善隱私和安全性。 - 提供一種 延遲載入腳本直到您需要它的方法。
對於腳本 API,它
- 為腳本的函數提供完全的類型安全
- 新增一個 Proxy 層,允許您的應用程式在不安全的環境中執行腳本函數(SSR、在載入腳本之前、腳本遭到封鎖)
const { proxy, onLoaded } = useScript('/hello.js', {
trigger: 'onNuxtReady',
use() {
return window.helloWorld
}
})
onLoaded(({ greeting }) => {
// ✅ script is loaded! Hooks into Vue lifecycle
})
// ✅ OR use the proxy API - SSR friendly, called when script is loaded
proxy.greeting() // Hello, World!
declare global {
interface Window {
helloWorld: {
greeting: () => 'Hello World!'
}
}
}
腳本註冊表
腳本註冊表是常見第三方腳本的第一方整合集合。截至發佈時,我們支援 21 個腳本,未來還會有更多腳本。
這些註冊表腳本是 useScript
的微調包裝器,具有完全的類型安全、腳本選項的執行階段驗證(僅限開發)和環境變數支援
例如,我們可以查看 Fathom Analytics 腳本。
const { proxy } = useScriptFathomAnalytics({
// ✅ options are validated at runtime
site: undefined
})
// ✅ typed
proxy.trackPageview()
外觀元件
註冊表包含數個 外觀元件,例如 Google 地圖、YouTube 和 Intercom。
外觀元件是在載入第三方腳本時水合化的「虛擬」元件。外觀元件有其優缺點,但可以大幅提升您的效能。請參閱 什麼是外觀元件?指南,以取得更多資訊。
Nuxt Scripts 提供外觀元件,這些元件可存取但無頭,這表示預設情況下它們沒有樣式,但會新增必要的 a16y 資料。

按一下以載入
同意管理和元素事件觸發器
useScript
可組合函式讓您可以完全控制腳本的載入方式和時間,方法是提供自訂 trigger
或手動呼叫 load()
函式。
在此外,Nuxt Scripts 提供進階觸發器,使其更容易使用。
const cookieConsentTrigger = useScriptTriggerConsent()
const { proxy } = useScript<{ greeting: () => void }>('/hello.js', {
// script will only be loaded once the consent has been accepted
trigger: cookieConsentTrigger
})
// ...
function acceptCookies() {
cookieConsentTrigger.accept()
}
// greeting() is queued until the user accepts cookies
proxy.greeting()
捆綁腳本
在許多情況下,我們是從我們無法控制的網域載入第三方腳本。這可能會導致許多問題
- 隱私:第三方腳本可以跨網站追蹤使用者。
- 安全性:第三方腳本可能會遭到入侵並注入惡意程式碼。
- 效能:額外的 DNS 查找會減慢頁面載入速度。
- 開發者體驗:已同意的腳本可能會遭到廣告封鎖程式封鎖。
為了減輕這種情況,Nuxt Scripts 提供一種將第三方腳本捆綁到您的公開目錄中的方法,無需任何額外工作。
useScript('https://cdn.jsdelivr.net/npm/js-confetti@latest/dist/js-confetti.browser.js', {
bundle: true,
})
腳本現在將會從您網域上的 /_scripts/{hash}
提供。
未完待續
正如我們所見,有很多機會可以改善開發人員和終端使用者的第三方腳本。
Nuxt Scripts 的初始版本已經解決了其中一些問題,但我們仍然有許多工作要做。
路線圖上的下一個項目是
我們很樂意獲得您的貢獻和支援。
開始使用
若要開始使用 Nuxt Scripts,我們建立了一個 教學課程,以協助您啟動並執行。
貢獻者
- Harlan Wilton - Nuxt (作者)
- Julien Huang - Nuxt (貢獻者)
- Daniel Roe - Nuxt (貢獻者)
- Chrome Aurora - Google (貢獻者)
並且非常感謝早期的貢獻者。