Nuxt Vitalizer
一个作为做好一件事的 Nuxt 模块的工作方法集合,用于优化 Google Lighthouse 和 Google PageSpeed Insights 中的最大内容ful Paint (LCP)。
此模块为以下 Nuxt 问题(以及其他问题)提供解决方案
- 禁用动态导入的
prefetch
(#18376) - 预取代码块的优化 (#14584)
inlineStyles
选项导致 CSS 重复 (#21821)
特性
- 🚀 零配置即可获得更好的 LCP
- 🫸 移除渲染阻塞 CSS
- 🔥
DelayHydration
组件,用于减少阻塞时间指标 - 💨
SkipHydration
组件,为初始渲染保留 SSR 内容
设置
npx nuxi@latest module add nuxt-vitalizer
使用方法
将 Nuxt Vitalizer 添加到您的 Nuxt 配置中,即可开始使用
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer']
})
要自定义模块,请在您的 Nuxt 配置中配置 vitalizer
选项
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
// Remove the render-blocking entry CSS
disableStylesheets: 'entry'
}
})
LCP 优化特性
应用此模块的优化特性后,您可以获得更高的 Lighthouse 性能评分
禁用动态导入的预取链接
!NOTE 此功能默认启用。
由于 HTML 中累积了大量的 <link rel="prefetch">
标签,大型 Nuxt 应用程序可能会在 Lighthouse 和 Google PageSpeed Insights 中遇到较差的性能评分。
对于每个动态导入,例如异步组件和其他资源(例如图像),都会渲染一个 prefetch
链接。这会导致浏览器预取这些代码块,即使当前页面不需要它们。虽然这对于应用程序的整体性能非常有利,但它可能导致大量的预取请求,从而对最大内容ful Paint 分数产生负面影响。
此模块钩入 Nuxt 构建过程,通过禁用动态导入的 prefetch
链接的渲染来优化 LCP 分数。
禁用预加载链接
!NOTE 此功能必须手动启用。
预加载链接用于预加载当前页面所需的关键资源。虽然它们通常在优化网站性能方面发挥作用,但如果使用不当,也可能导致大量的请求。删除预加载链接可以帮助提高 FCP(首次内容ful Paint)分数,尤其是在网络条件较慢的情况下。
要删除预加载构建资源,请将 disablePrefetchLinks
选项设置为 true
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
disablePrefetchLinks: true
}
})
停止渲染阻塞 CSS
!NOTE 此功能必须手动启用。要使用它,您需要启用 Nuxt 的
inlineStyles
功能。启用此选项后,请务必测试您的应用程序。
CSS 样式表是渲染阻塞资源,这意味着浏览器必须先下载并解析 CSS,然后才能渲染页面。通过使用内联样式而不是加载样式表,浏览器可以更快地渲染页面,从而可以提高 LCP 分数。
虽然最新的 Nuxt 版本在 SSR 渲染期间内联样式,但 entry.<hash>.css
样式表仍然在 HTML 中渲染。这可能导致渲染阻塞 CSS,从而对最大内容ful Paint 分数产生负面影响。
为什么会这样?正如 Nuxt 核心团队成员 @danielroe 所解释的
我认为这是当前内联样式实现的局限性。
在您的应用程序中到处使用的样式可以安全地从 CSS 源代码中完全删除。但是仅在一个组件或页面中使用的 CSS 需要位于 CSS 文件中以及内联。
目前,vite 完全负责在客户端加载 CSS,这意味着即使我们跟踪了已经加载的 CSS,我们也无法阻止 vite 加载包含重复 CSS 的 CSS 文件。
这绝对是我希望看到修复的事情。
首先,尝试在 app.vue
文件中导入主应用程序样式。当构建 Nuxt 时,它们将被保存为 entry
CSS 文件
// `app.vue`
import '~/assets/css/main.css'
现在,将 disableStylesheets
选项设置为 entry
,以防止 entry.<hash>.css
样式表在 HTML 中渲染
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
disableStylesheets: 'entry'
}
})
组件
DelayHydration
!WARNING 延迟组件 hydration 是一种欺骗 Lighthouse,使其认为页面比实际更早可交互的 hack 方法。它可能无法提供实际的性能改进,应谨慎使用。
延迟 hydration 是一种向 Lighthouse 提示页面比实际更早可交互的技术。这可以改善 Lighthouse 和 Google PageSpeed Insights 中的“阻塞时间”指标。
DelayHydration
组件是一个简单的组件,它在 hydration 组件之前等待一定的时间。当您有很多网络请求正在发生并且想要延迟组件的 hydration 直到网络请求完成时,这可能很有用。
组件用法
在您的 Vue 组件中使用 DelayHydration
组件
<template>
<div>
<DelayHydration>
<!-- Ensure to lazy load the component -->
<LazyMyExpensiveComponent />
</DelayHydration>
</div>
</template>
配置
您可以在 vitalizer
模块选项中配置 DelayHydration
组件
// `nuxt.config.ts`
export default defineNuxtConfig({
modules: ['nuxt-vitalizer'],
vitalizer: {
delayHydration: {
hydrateOnEvents: ['mousemove', 'scroll', 'keydown', 'click', 'touchstart', 'wheel'],
idleCallbackTimeout: 8000,
postIdleTimeout: 4000
}
}
})
hydrateOnEvents
选项指定应触发 hydration 的事件。默认情况下,当用户移动鼠标、滚动、按键、单击、触摸屏幕或滚动鼠标滚轮时,组件将立即 hydration。idleCallbackTimeout
选项指定等待空闲回调时要等待的最大时间(以毫秒为单位)。当有很多网络请求正在发生时,这很有用。postIdleTimeout
选项指定在空闲回调后等待 hydration 组件的时间(以毫秒为单位)。
SkipHydration
SkipHydration
组件只是阻止其子组件在客户端上进行初始渲染的 hydration。换句话说,只要组件未卸载,SSR 内容就会保持不变。当首次访问页面时,没有必要 hydration 特定组件来节省加载组件代码块时,这可能很有用。
当导航到新页面时,SkipHydration
组件将在客户端上挂载其子组件,并且行为类似于普通的 Vue 组件。
组件用法
在您的 Vue 组件中使用 SkipHydration
组件
<template>
<div>
<SkipHydration>
<!-- Ensure to lazy load the component -->
<LazyMyExpensiveComponent />
</SkipHydration>
</div>
</template>
模块选项
interface ModuleOptions {
/**
* Whether to remove prefetch links from the HTML. If set to `dynamicImports`, only dynamic imports will be removed. To disable all prefetching, such as images, set to `true`.
*
* @remarks
* This will prevent the browser from downloading chunks that may not be needed yet. This can be useful for improving the LCP (Largest Contentful Paint) score.
*
* @default 'dynamicImports'
*/
disablePrefetchLinks?: boolean | 'dynamicImports'
/**
* Whether to remove preload links from the HTML. This can be useful for improving the FCP (First Contentful Paint) score, especially when emulating slow network conditions.
*
* @default false
*/
disablePreloadLinks?: boolean
/**
* Whether to remove the render-blocking stylesheets from the HTML. This only makes sense if styles are inlined during SSR rendering. To only prevent the `entry.<hash>.css` stylesheet from being rendered, set to `entry`. If set to `true`, all stylesheet links will not be rendered.
*
* @remarks
* This requires to have the Nuxt `inlineStyles` feature enabled. Make sure to test your application after enabling this option.
*
* @default false
*/
disableStylesheets?: boolean | 'entry'
/**
* Options for the `DelayHydration` component.
*/
delayHydration?: {
/**
* Specify the events that should trigger hydration.
*
* @default ['mousemove', 'scroll', 'keydown', 'click', 'touchstart', 'wheel']
*/
hydrateOnEvents?: (keyof WindowEventMap)[]
/**
* The maximum amount of time to wait in milliseconds when waiting for an idle callback. This is useful when there are a lot of network requests happening.
*
* @default 8000
*/
idleCallbackTimeout?: number
/**
* Time to wait in milliseconds after the idle callback before hydrating the component.
*
* @default 4000
*/
postIdleTimeout?: number
}
}
💻 开发
- 克隆此仓库
- 使用
corepack enable
启用 Corepack - 使用
pnpm install
安装依赖项 - 运行
pnpm run dev:prepare
- 使用
pnpm run dev
启动开发服务器
鸣谢
- Nuxt GitHub 问题中所有启发此模块的讨论和贡献。
- @harlan-zw,感谢他鼓舞人心的 nuxt-delay-hydration 模块。
许可证
MIT 许可证 © 2024-PRESENT Johann Schopplich