通过 100+ 条技巧学习 Nuxt!

delay-hydration
nuxt-delay-hydration

通过延迟水合来提高您的 Nuxt v2 Google Lighthouse 分数。

nuxt-delay-hydration

NPM Downloads


状态: 稳定 v2 v0 ✅ , v3 main
由我的 赞助计划 💖 提供支持
关注我 @harlan_zw 🐦

⚠️ 这是一个“黑客”技巧,用于欺骗 Google Lighthouse,使其认为您的网站比实际速度更快。

  • 它应该只用于渐进增强型网站。
  • 它可能不会提供任何真正的性能或 SEO 优势(使用 CrUX 而不是 Google Lighthouse 进行测试)。

功能特性

  • 🔥 减少您网站的“阻塞时间”
  • 🚦 使用路由规则进行页面级配置
  • 🔁 (可选)重放预水合点击

为什么要延迟水合?

延迟水合是一种提示 Google 我们的脚本不是我们应用程序运行所必需的技术。

通过延迟水合,我们通过减少您的“阻塞时间”指标来提高 Google Lighthouse 分数。

以前您可能使用过 vue-lazy-hydration,它效果很好。但是,它只是一种更冗长的方式来向 Google 提供提示,就像我们使用此模块所做的那样。


什么是渐进增强型应用?

渐进增强型应用是指旨在在没有 JavaScript 的情况下工作,然后通过 JavaScript 逐步增强的应用。

您的网站不应依赖脚本才能使用,这就是我们通过延迟水合向 Google 提示的内容。

为此,您可以确保

  • 初始响应中提供完整的 HTML
  • 脚本不会触发 CLS
  • 避免使用脚本设置图像,这会影响 LCP

此模块的工作原理
一个 Promise 被注入到您的应用程序中,位置基于模式。一旦以下任一事件触发,Promise 就会被解决
  • 交互事件(鼠标移动、滚动、点击等)
  • 具有固定超时时间的空闲回调

空闲 CPU 时间向 Google 提示这些脚本不是您的应用程序运行所必需的。

例如

  • 如果 Google 机器人访问页面且没有交互,则开箱即用水合将不会发生,直到浏览器空闲回调 + 6 秒
  • 如果用户访问页面并移动光标或滚动,则会立即触发水合。与非水合应用程序交互的机会将降至最低

请记住,这是一个权宜之计。在 Google 能够识别渐进式脚本增强功能之前,我们将需要依赖这种方法。


安装

如果您使用的是 Nuxt 2.x,请按照 v0 分支上的文档进行操作。 ⚠️ Nuxt 2 已弃用,不会获得支持。

npx nuxi@latest module add delay-hydration

要求:渐进增强型 SSR 或 SSG Nuxt 应用程序。


用法

// nuxt.config.ts
export default {
  modules: [
    'nuxt-delay-hydration',
  ],
  delayHydration: {
    // enables nuxt-delay-hydration in dev mode for testing
    // NOTE: you should disable this once you've finished testing, it will break HMR
    debug: process.env.NODE_ENV === 'development'
  }
}

注意:除非您启用 debug,否则该模块不会在开发环境中运行。

选择模式

默认情况下,未选择任何模式,您需要选择您希望模块如何工作。

类型: init | mount| manual | false

默认值: false

类型描述用例
false 默认禁用模块测试
init延迟加载所有脚本。零个或最少的插件/模块。
mount 推荐在 Nuxt 挂载时延迟 Nuxt。插件和一些第三方脚本将起作用。最少的非关键插件和第三方插件。
manual延迟由 DelayHydration 组件提供。所有其他应用程序

无论您选择哪种模式,请阅读 进一步优化

Init 模式

此模式延迟加载所有脚本,直到水合 Promise 被解决。

它通过钩入 HTML 渲染,删除所有脚本标签并在水合 Promise 被解决后将其添加回来来实现这一点。

这将提供最大的速度提升,但也是风险最高的。

优点: 提供最大的阻塞时间减少

缺点: 如果您有关键的第三方脚本,则有风险

基准测试: 约 90-100% 的减少

export default {
  delayHydration: {
    mode: 'init'
  }
}

Mount 模式

此模式在 Nuxt 挂载时延迟 Nuxt。插件和一些第三方脚本将起作用。

这将延迟您的布局和页面组件。

优点: 更安全,并且仍然提供良好的改进

缺点: 如果某些布局依赖于 js,则可能仍然会破坏这些布局。

基准测试: 约 70% 的减少

export default {
  delayHydration: {
    mode: 'mount'
  }
}

Manual 模式

使用手动模式,您可以手动指定要延迟应用程序的哪个部分。当您需要页面的某些部分始终立即水合时非常有用,例如导航抽屉。

优点: 最安全的优化方式

缺点: 速度提升取决于使用情况

export default {
  delayHydration: {
    mode: 'manual'
  }
}

DelayHydration 组件

设置模式后,您需要使用该组件。

<template>
  <div>
    <DelayHydration>
      <div>
        <LazyMyExpensiveComponent />
      </div>
    </DelayHydration>
  </div>
</template>

指南

按页面配置

您可以使用路由规则在每个页面上配置模块。

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // delay the home page
    '/': { delayHydration: 'mount' },
    // disable the module for the admin
    '/admin/': { delayHydration: false }
  }
})

您还可以使用 defineRouteRules 在页面级别定义它们。

调试

调试模式
建议您在将模块部署到生产环境之前,对您的应用程序进行彻底的测试。

为了确保模块按您的预期工作,有一个 debug 模式,启用后将在控制台中记录行为。

在本地环境中始终进行调试可能是一个好主意,在这种情况下,您可以这样做

export default defineNuxtConfig({
  delayHydration: {
    debug: process.env.NODE_ENV === 'development',
  },
})

可视化水合状态
有时可能不清楚您的应用程序是否已水合,如果它非常静态,这会使调试变得困难。

为了简化操作,有一个 HydrationStatus 组件可以告诉您正在发生的事情。

<template>
  <div>
    <MyHeader />
    <DelayHydration>
      <div>
        <!-- Show the hydration status, only for debugging -->
        <HydrationStatus />
        <main>
          <nuxt />
        </main>
        <my-footer />
      </div>
    </DelayHydration>
  </div>
</template>

性能审计

使用我的审计工具:https://unlighthouse.dev/

重放水合点击

这是什么以及如何启用
延迟水合的问题之一是,用户交互事件可能在您的脚本加载之前发生,导致用户必须多次单击某些内容才能使其执行他们期望的操作。想想使用 Javascript 触发的汉堡菜单,如果您的应用程序未水合,则单击它将不会执行任何操作。

对此的最佳解决方案是以 不需要 Javascript 的方式编写您的 HTML 以使其具有交互性。

但是,在某些用例中,您需要使用 Javascript,并且响应首次点击非常重要。在这些情况下,您可以启用点击重放。

export default defineNuxtConfig({
  delayHydration: {
    replayClick: true
  },
})

这是一个实验性配置,您应该在将其部署到生产应用程序之前自行测试此选项。

进一步优化

异步加载重型组件
当您同步加载重型组件时,javascript 将与主应用程序有效负载捆绑在一起。

这将降低您的所有性能指标。建议您对这些组件使用异步导入。

运行 nuxi analyze 以查找大型组件。加载它们时,在其前面加上 Lazy

高级配置

配置应在您的 Nuxt 配置中的 delayHydration 键上提供。

如果您发现实验室或 现场数据 表现不佳,您可能需要调整此高级配置。

过滤路由

注意:建议使用路由规则而不是这些过滤选项。

使用 includeexclude 选项,您可以指定要在哪些路由上延迟水合。

// nuxt.config.ts
export default defineNuxtConfig({
  delayHydration: {
    include: [
      '/blog/**',
    ],
    exclude: [
      '/admin/**'
    ],
  },
})

您可以提供类似于路由规则的 glob 模式或正则表达式。

事件水合

hydrateOnEvents

  • 类型:string[]
  • 默认值:[ 'mousemove', 'scroll', 'keydown', 'click', 'touchstart', 'wheel' ]

控制哪些浏览器事件应触发水合恢复。默认情况下,它非常激进,以避免可能的用户体验问题。

replayClick

  • 类型:boolean
  • 默认值:false

如果水合的触发器是单击,您可以重放它。重放它将在假定您的应用程序已水合时重新执行该事件。

例如,如果用户单击汉堡菜单图标并且需要水合才能打开菜单,它将在水合后重放单击。

⚠️ 这是实验性的,请谨慎使用。

空闲水合

idleCallbackTimeout

  • 类型:number (毫秒)
  • 默认值:7000

在等待空闲回调时,可以定义最大等待时间(以毫秒为单位)。当发生大量网络请求时,这很有用。

postIdleTimeout

  • 类型:{ mobile: number, desktop: number } (毫秒)
  • 默认值:{ mobile: 5000, desktop: 4000, }

在空闲回调后等待多长时间(以毫秒为单位)才恢复水合。这个额外的超时是避免标准“阻塞”所必需的,我们需要为 lighthouse 提供真正的空闲时间。

移动设备的默认值应始终高于桌面设备,因为 CPU 容量通常远小于桌面设备。

注意:默认值将来可能会根据进一步的基准测试进行自定义。

调试

debug

  • 类型:boolean
  • 默认值:false

在控制台中记录何时阻止水合以及何时以及为何解除阻止水合的详细信息。

基准测试

实时示例

鸣谢

赞助商

许可证

MIT 许可证 © 2022 - 至今 Harlan Wilton