Nuxt Nation 大会即将到来。加入我们,时间为 11 月 12 日至 13 日。

vitalizer
nuxt-vitalizer

在 Google Lighthouse 中立即获得更好的 LCP 分数

Nuxt Vitalizer module

Nuxt Vitalizer

作为做好一件事Nuxt模块,提供了一系列解决方法,用于优化 Google Lighthouse 和 Google PageSpeed Insights 中的最大内容绘制 (LCP)。

此模块为以下 Nuxt 问题(以及其他问题)提供了解决方案

功能

  • 🚀 无需配置即可获得更好的 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 性能分数

Lighthouse SEO performance score when using the module

!注意 此功能默认启用。

大型 Nuxt 应用程序在 Lighthouse 和 Google PageSpeed Insights 中可能会遇到性能得分较差的问题,这是由于 HTML 中累积了<link rel="prefetch">标签。

对于每个动态导入(例如异步组件和其他资产,如图像),都会渲染一个prefetch链接。这会导致浏览器预取这些 chunk,即使它们在当前页面上不需要。虽然这对应用程序的整体性能很有帮助,但它可能导致大量的预取请求,从而对最大内容绘制分数产生负面影响。

此模块挂接到 Nuxt 构建过程中,通过禁用为动态导入渲染prefetch链接来优化 LCP 分数。

!注意 此功能需要手动启用。

预加载链接用于预加载当前页面所需的关键资源。虽然它们通常在优化网站性能方面发挥作用,但如果使用不当,也可能导致大量请求。删除预加载链接有助于提高 FCP(首次内容绘制)分数,尤其是在网络连接较慢的情况下。

要删除预加载构建资源,请将disablePrefetchLinks选项设置为true

// `nuxt.config.ts`
export default defineNuxtConfig({
  modules: ['nuxt-vitalizer'],

  vitalizer: {
    disablePrefetchLinks: true
  }
})

停止阻止渲染的 CSS

!注意 此功能需要手动启用。要使用它,您需要启用 Nuxt inlineStyles功能。启用此选项后,请确保测试您的应用程序。

CSS 样式表是阻止渲染的资源,这意味着浏览器必须下载并解析 CSS 才能渲染页面。通过使用内联样式而不是加载样式表,浏览器可以更快地渲染页面,从而提高 LCP 分数。

虽然最新的 Nuxt 版本在 SSR 渲染期间内联样式,但entry.<hash>.css样式表仍在 HTML 中渲染。这可能导致阻止渲染的 CSS,从而对最大内容绘制分数产生负面影响。

为什么会这样?正如Nuxt 核心团队成员 @danielroe 所解释的

我认为这是当前内联样式实现的一个限制。

应用到处使用的样式可以安全地完全从 CSS 源代码中删除。但是,仅在一个组件或页面中使用的 CSS 需要位于 CSS 文件中,以及内联。

目前,vite 完全负责在客户端加载 CSS,这意味着即使我们跟踪了已加载的 CSS,我们也无法阻止 vite 加载包含重复 CSS 的 CSS 文件。

这是我绝对希望看到修复的内容。

首先,尝试在app.vue文件中导入主应用程序样式。当 Nuxt 构建时,它们将被保存为entryCSS 文件

// `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

!警告 延迟组件的水合是一个技巧,可以欺骗 Lighthouse 认为页面比实际更早地具有交互性。它可能无法提供真实的性能改进,应谨慎使用。

延迟水合是一种技巧,可以提示 Lighthouse 认为页面比实际更早地具有交互性。这可以提高 Lighthouse 和 Google PageSpeed Insights 中的“阻塞时间”指标。

DelayHydration组件是一个简单的组件,它等待一段时间后才水合组件。当您有很多网络请求正在发生并且想要延迟组件的水合直到网络请求完成时,这很有用。

组件用法

在您的 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选项指定应触发水合的事件。默认情况下,当用户移动鼠标、滚动、按下键、点击、触摸屏幕或滚动鼠标滚轮时,组件将立即水合。
  • idleCallbackTimeout选项指定在等待空闲回调时等待的最长时间(以毫秒为单位)。当有很多网络请求正在发生时,这很有用。
  • postIdleTimeout选项指定在空闲回调后等待多长时间(以毫秒为单位),然后再水合组件。

SkipHydration

SkipHydration组件只是防止其子元素在初始渲染时在客户端水合。换句话说,只要组件未卸载,SSR 内容就会保留。当首次访问页面时不需要水合特定组件以节省加载组件 chunk 时,这很有用。

导航到新页面时,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
  }
}

💻 开发

  1. 克隆此存储库
  2. 使用corepack enable启用Corepack
  3. 使用pnpm install安装依赖项
  4. 运行pnpm run dev:prepare
  5. 使用pnpm run dev启动开发服务器

鸣谢

许可证

MIT 许可证 © 2024-至今 Johann Schopplich