关键概念

了解 Nuxt Scripts 的关键概念。

useScript 组合式函数是 Nuxt Scripts 的核心,用于加载所有脚本。

useScript 之上构建了额外的抽象层,使得以不同方式加载脚本变得更加容易。

  1. 注册脚本 - 预配置的第三方脚本,可以通过 Nuxt 配置、组合式函数和组件加载。
  2. 全局脚本 - 通过 Nuxt 配置文件加载脚本。

Unhead 抽象层

Nuxt Scripts 的 useScript 组合式函数是对 Unhead 的 useScript 的抽象,而后者又是基于 useHead 的抽象。通过 useHead 可用的许多功能,在 Nuxt Scripts 的 useScript 中也能使用。

脚本单例

在 Nuxt Scripts 中,不可能多次加载相同 src(或 key)的脚本。这是因为脚本是全局加载的,并且在所有组件间共享。

这意味着脚本只会经过一次初始化过程,后续对 useScript 的调用都会返回同一实例。

因此,你可以考虑将 useScript 调用封装在自己的组合式函数中,以便更方便地实例化该脚本。

useMyScript.ts
export function useMyScript() {
  return useScript({
    src: 'https://example.com/script.js',
  })
}

默认行为

Nuxt Scripts 不会在 SSR 响应中插入脚本标签。这是一个性能决策,旨在最大限度地减少对 hydration 过程的干扰。相反,脚本默认会在 Nuxt 完全在客户端完成 hydration 后加载。

你可以通过修改 defaultScriptOptions 来改变此行为。

Nuxt Scripts 还会向 <script> 标签插入若干额外的属性,以优化性能和隐私。

  • async - 脚本异步加载,防止阻塞页面渲染。
  • defer - 脚本延迟执行,确保按加载顺序执行。
  • crossorigin="anonymous" - 脚本带有 anonymous 属性,防止访问 Cookie。
  • referrerpolicy="no-referrer" - 脚本使用 no-referrer 策略,防止发送 Referer 头。
  • fetchpriority="low" - 脚本以较低优先级加载,提升页面性能。

注意: 默认不使用 async,而是使用 defer。如果需要 async,你可以显式禁用 defer

理解代理函数

你可能会好奇 useScript 组合式函数如何返回 SSR 安全的函数,并且可以在脚本加载前调用。

const { proxy } = useScript('/script.js')
// 如你所愿地工作 —— 魔法吗?
proxy.gtag('event', 'page_view')

gtag 函数调用是一个代理,函数会被排队,等脚本加载后才执行。如果脚本从未加载,则函数不会被调用。

这带来了几个优点:

  • SSR 安全
  • 如果脚本未加载(被广告拦截器阻止),不会破坏你的网站
  • 允许随时加载脚本,无需担心脚本和函数调用的顺序

但也有一些缺点:

  • 仅适用于不需要返回值的函数。你可以等待函数调用来获取返回值,但这会阻塞页面渲染。
  • 如果不了解其工作原理,调试时可能会感到困惑。

如果你想直接访问脚本的 API,建议等待脚本加载完成后再调用。

const { onLoaded } = useScript('/script.js')
// 直接使用脚本实例,而非代理
onLoaded(({ gtag }) => {
  gtag('event', 'page_view')
})