状态:稳定版 v2 v0 ✅ , v3 main ✅ 由我的赞助计划 💖 提供支持 关注我 @harlan_zw 🐦 |
⚠️ 这是一种“技巧”,可以欺骗 Google Lighthouse,让它认为您的网站比实际速度更快。
- 它应该只用于渐进增强的网站。
- 它可能不会提供任何真正的性能或 SEO 好处(使用 CrUX 测试,而不是 Google Lighthouse)。
特性
- 🔥 减少您网站的“阻塞时间”
- 🚦 使用路由规则进行页面级配置
- 🔁(可选)重播预水合点击
为什么要延迟水合?
延迟水合是一种向 Google 暗示我们的脚本不是我们应用程序运行所必需的技术。
通过延迟水合,我们可以通过减少“阻塞时间”指标来提高 Google Lighthouse 分数。
以前您可能使用过 vue-lazy-hydration,它效果很好。但是,这只是一种向 Google 提供提示的更详细的方式,就像我们使用此模块所做的那样。
什么是渐进增强的应用程序?
渐进增强的应用程序是指设计为在没有 JavaScript 的情况下工作,然后通过 JavaScript 逐步增强的应用程序。
您的脚本不应该是使用您的网站所必需的,这就是我们通过延迟水合来暗示 Google 的内容。
要做到这一点,您可以确保
此模块的工作原理
一个 Promise 被注入到您的应用程序中,位置基于模式。只要以下任一事件触发,Promise 就会被解决
- 交互事件(鼠标移动、滚动、点击等)
- 具有固定超时时间的空闲回调
空闲 CPU 时间向 Google 暗示这些脚本不是您的应用程序运行所必需的。
例如
- 如果 Google 机器人访问该页面且没有交互,默认情况下,水合将在浏览器空闲回调 + 6 秒后才会发生
- 如果用户访问该页面并移动他们的光标或滚动,则水合将立即触发。与非水合应用程序交互的机会将被最小化
请记住,**这是一个 hacky 解决方案**。在 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 挂载时延迟它。插件和一些第三方脚本将起作用。 | 最少量的非关键插件和第三方插件。 |
manual | 延迟由 DelayHydration 组件提供。 | 所有其他应用 |
无论您选择哪种模式,请阅读 进一步优化。
Init 模式
此模式延迟所有脚本的加载,直到水合 Promise 被解决。
它通过挂钩到 HTML 渲染来实现这一点,删除所有 script 标签并在水合 Promise 被解决后将其添加回来。
这将提供最大的速度提升,但是风险也最大。
优点:提供最大的阻塞时间减少
缺点:如果您有关键的第三方脚本,则有风险
基准: ~90-100% 的减少
export default {
delayHydration: {
mode: 'init'
}
}
Mount 模式
此模式在 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
键上提供。
如果您发现实验室或 现场数据没有执行,您可能需要调整此高级配置。
过滤路由
注意:建议使用路由规则而不是这些过滤选项。
使用 include
和 exclude
选项,您可以指定要在哪些路由上延迟水合。
// 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
在控制台中记录水合何时被阻止,以及何时以及为何解除阻止的详细信息。
基准测试
在线示例
鸣谢
- Markus Oberlehner. Vue 中惰性水合的先驱
赞助商
许可证
MIT 许可证 © 2022 - 至今 Harlan Wilton