Nuxt 性能

提升 Nuxt 应用性能的最佳实践。

Nuxt 内置了旨在提升应用性能并有助于实现更好的核心网页指标 (Core Web Vitals)的功能。此外,还有多个 Nuxt 核心模块可协助提升特定领域的性能。本指南概述了优化 Nuxt 应用性能的最佳实践。

内置功能

Nuxt 提供了多种内置功能,帮助您优化网站性能。了解这些功能的工作原理对于实现极速性能至关重要。

<NuxtLink> 是 Vue Router 的 <RouterLink> 组件和 HTML 的 <a> 标签的直接替代品。它能智能判断链接是内部还是外部,并相应地利用现有优化(预取、默认属性等)进行渲染。

<template>
  <NuxtLink to="/about">About page</NuxtLink>
</template>

<!-- Which will render to with Vue Router & Smart Prefetching -->
<a href="/about">About page</a>

Nuxt 自动包含智能预取功能。这意味着它能检测链接何时可见(默认情况下),无论是在视口中还是在滚动时,并预取这些页面的 JavaScript,以便在用户点击链接时即刻加载。

您也可以选择在交互时进行预取

export default defineNuxtConfig({
  experimental: {
    defaults: {
      nuxtLink: {
        prefetchOn: 'interaction',
      },
    },
  },
})
阅读更多关于 NuxtLink 的内容。

混合渲染

在复杂的应用中,我们可能需要完全控制应用的渲染方式,以支持某些页面在构建时生成,而另一些页面则进行客户端渲染的情况。

混合渲染允许使用路由规则(Route Rules)为每个路由设置不同的缓存规则,并决定服务器应如何响应给定 URL 的新请求。

export default defineNuxtConfig({
  routeRules: {
    '/': {
      prerender: true,
    },
    '/products/**': {
      swr: 3600,
    },
    '/blog': {
      isr: 3600,
    },
    '/admin/**': {
      ssr: false,
    },
  },
})

Nuxt 服务器将自动注册相应的中间件,并使用 Nitro 缓存层包装带有缓存处理程序的路由。

阅读更多关于 混合渲染 (Hybrid rendering) 的内容。

组件懒加载

要动态导入组件(也称为组件懒加载),您只需在组件名称前添加 Lazy 前缀。这在组件并非总是需要时非常有用。

<script setup lang="ts">
const show = ref(false)
</script>

<template>
  <div>
    <h1>Mountains</h1>
    <LazyMountainsList v-if="show" />
    <button v-if="!show" @click="show = true">Show List</button>
  </div>
</template>

通过使用 Lazy 前缀,您可以将组件代码的加载推迟到合适的时机,这有助于优化您的 JavaScript 包大小。

阅读更多关于 组件懒加载 的内容。

懒水合 (Lazy Hydration)

并非总是需要在初始加载时对网站的所有组件进行水合(或使其具有交互性)。通过使用懒水合,您可以控制组件何时加载代码,这可以改善应用的“交互时间”指标。Nuxt 允许您通过懒水合(于 Nuxt v3.16 引入)来控制组件何时变得具有交互性。

<template>
  <div>
    <LazyMyComponent hydrate-on-visible />
  </div>
</template>

为了优化应用,您可能希望将某些组件的水合推迟到它们可见时,或者推迟到浏览器完成更重要的任务之后。

阅读更多关于 懒水合 的内容。

数据获取

为了避免重复获取相同数据(分别在服务器和客户端各获取一次),Nuxt 提供了 useFetchuseAsyncData。它们确保如果 API 调用是在服务器上进行的,数据会随载荷(payload)转发到客户端,而不是再次获取。

阅读更多关于 数据获取 的内容。

Nuxt 核心模块

除了 Nuxt 的内置功能外,还有由 Nuxt 团队维护的核心模块,它们有助于进一步提升性能。这些模块有助于处理图像、自定义字体或第三方脚本等资源。

图片

未经优化的图像会对您的网站性能产生重大负面影响,特别是最大内容渲染时间 (LCP)评分。

在 Nuxt 中,我们可以使用Vercel 上使用 Nuxt Image模块,它是 Nuxt 应用的即插即用型图像优化方案。它允许您使用内置优化器或您喜爱的图像 CDN 来调整和转换图像大小。

<NuxtImg> 是原生 <img> 标签的直接替代品,它具有以下增强功能:

  • 使用内置提供程序优化本地和远程图像
  • src 转换为提供程序优化的 URL,并支持 WebP 或 Avif 等现代格式
  • 根据 widthheight 自动调整图像大小
  • 在提供 sizes 选项时自动生成响应式 sizes
  • 支持原生的 lazy loading 以及其他 <img> 属性

网站中的图像通常可以按重要性进行划分;那些在初始加载时必须先交付的图像(例如 最大内容渲染时间),以及那些可以稍后或在特定需要时加载的图像。为此,我们可以使用以下优化方案

<template>
  <!-- 🚨 Needs to be loaded ASAP -->
  <NuxtImg
    src="/hero-banner.jpg"
    format="webp"
    :preload="{ fetchPriority: 'high' }"
    loading="eager"
    width="200"
    height="100"
  />

  <!-- 🐌 Can be loaded later -->
  <NuxtImg
    src="/facebook-logo.jpg"
    format="webp"
    loading="lazy"
    fetchpriority="low"
    width="200"
    height="100"
  />
</template>
阅读更多关于 Nuxt Image 的内容。

字体

Nuxt Fonts会自动优化您的字体(包括自定义字体)并移除外部网络请求,以提升隐私和性能。

它包含内置的自动字体自托管功能,这意味着您可以最佳地加载 Web 字体,同时减少布局偏移,这得益于底层包fontaine.

Nuxt Fonts 会处理您所有的 CSS,并在遇到 font-family 声明时自动执行以下操作。

  1. 解析字体 – 在 public/ 中查找字体文件,然后检查 Google、Bunny 和 Fontshare 等 Web 提供商。
  2. 生成 @font-face 规则 – 注入 CSS 规则以从正确的源加载字体。
  3. 代理和缓存字体 – 将 URL 重写为 /_fonts,并下载并在本地缓存字体。
  4. 创建回退指标 – 调整本地系统字体以匹配 Web 字体,从而减少布局偏移(CLS).
  5. 将字体包含在构建中 – 将字体与您的项目打包在一起,对文件名进行哈希处理并设置长期缓存标头。

它支持多个可插拔和可扩展的提供程序,因此无论您的设置如何,您都应该能够使用现有的提供程序或编写自己的提供程序。

脚本

诸如分析工具、视频嵌入、地图和社交媒体集成等第三方资源增强了网站功能,但可能会严重降低用户体验并对下一帧渲染的交互时间 (INP)和最大内容渲染时间 (LCP) 评分产生负面影响。

Nuxt Scripts允许您以更好的性能、隐私、安全性和开发体验 (DX) 加载第三方脚本。

Nuxt Scripts 在第三方脚本之上提供了一个抽象层,提供 SSR 支持和类型安全,同时仍让您能完全底层控制脚本的加载方式。

const { onLoaded, proxy } = useScriptGoogleAnalytics(
  {
    id: 'G-1234567',
    scriptOptions: {
      trigger: 'manual',
    },
  },
)
// queue events to be sent when ga loads
proxy.gtag('config', 'UA-123456789-1')
// or wait until ga is loaded
onLoaded((gtag) => {
  // script loaded
})
阅读更多关于 Nuxt Scripts 的内容。

性能分析工具

为了提高性能,我们需要首先知道如何衡量它,从在开发环境(本地环境)中衡量性能开始,然后转向对生产环境部署的应用进行审计。

Nuxi Analyze

该命令nuxi 的命令,允许分析 Nuxt 应用的生产包。它利用 vite-bundle-visualizer(类似于 webpack-bundle-analyzer)来生成应用包的可视化表示,从而更容易识别哪些组件占用了最多的空间。

当您在可视化中看到一个大块时,这通常意味着存在优化的机会——无论是将其拆分为更小的部分、实施懒加载,还是用更高效的替代方案(特别是针对第三方库)来替换它。

包含多个元素的大块通常可以通过仅导入必要的组件而不是整个模块来缩减,而大型独立块可能更适合懒加载,而不是包含在主包中。

Nuxt DevTools

用于格式化的Nuxt DevTools为您提供关于 Nuxt 应用的见解和透明度,以识别性能差距并无缝管理您的应用配置。

它带有一些我们可以用来衡量 Nuxt 应用性能的功能

  1. 时间轴 (Timeline) – 跟踪渲染、更新和初始化组件所花费的时间,以识别性能瓶颈。
  2. 资产 (Assets) – 显示文件大小(例如图像),不进行转换。
  3. 渲染树 (Render Tree) – 显示 Vue 组件、脚本和样式之间的连接,以优化动态加载。
  4. 检查 (Inspect) – 列出 Vue 应用中使用的所有文件及其大小和评估时间。

Chrome DevTools

Chrome DevTools 带有两个有用的标签页用于衡量性能:PerformanceLighthouse

当您打开性能面板时,它会立即显示您本地的 最大内容渲染时间 (LCP)累积布局偏移 (CLS) 评分(好、需要改进或差)。

如果您与页面交互,它还会捕获 下一帧渲染的交互时间 (INP),让您根据设备和网络完整查看核心网页指标。

Lighthouse审计性能、可访问性、SEO、渐进式 Web 应用和最佳实践。它在您的页面上运行测试并生成报告。将审计结果作为改进网站的指南。

每个审计都有一个参考文档,解释为什么该审计很重要,以及如何修复它。

PageSpeed Insights

PageSpeed Insights (PSI)报告页面在移动设备和桌面设备上的用户体验,并提供有关如何改进该页面的建议。

它提供有关页面的实验室和现场数据。实验室数据对于调试问题很有用,因为它是在受控环境中收集的,而现场数据对于捕获真实的、现实世界中的用户体验很有用。

Web Page Test

WebPageTest是一个 Web 性能工具,提供有关页面在各种条件下如何表现的深入诊断信息。

每个测试都可以从世界各地的不同地点、在真实浏览器上、在任何数量的可自定义网络条件下运行。

常见问题

在构建更复杂的 Nuxt 应用时,您可能会遇到下面列出的一些问题。了解这些问题并修复它们将有助于您提高网站性能。

过度使用插件

问题:大量的插件会导致性能问题,特别是如果它们需要昂贵的计算或初始化时间过长。由于插件在水合阶段运行,效率低下的设置会阻止渲染并降低用户体验。

解决方案:检查您的插件,看看其中一些是否可以改为实现为可组合函数(composable)或工具函数。

未使用的代码/依赖项

问题:随着项目的开发,可能会出现一些未使用的代码或依赖项。这些额外的功能可能未被使用或不需要,但会增加项目的包大小。

解决方案:检查您的 package.json 中是否有未使用的依赖项,并分析您的代码中是否存在未使用的工具/可组合函数/函数。

未使用 Vue 性能提示

问题: Vue 文档列出了我们在 Nuxt 项目中也可以使用的几种性能改进方法,但由于它们是 Vue 文档的一部分,开发人员往往会忘记这一点,而只关注 Nuxt 特定的改进——尽管 Nuxt 应用仍然是一个 Vue 项目。

解决方案:使用 shallowRefv-memov-once 等概念来提高性能。

不遵循模式

问题:当前参与项目的人员越多,维护稳定的代码库就越困难。开发人员倾向于引入他们在其他项目中看到的、可能会导致冲突和性能问题的概念。

解决方案:在项目中建立规则和模式,例如Vue 可组合函数的良好实践和设计模式

试图同时加载所有内容

问题:当页面加载时,如果未正确指示元素加载顺序,将导致同时获取所有内容——这可能很慢并导致糟糕的用户体验。

解决方案:使用渐进增强(Progressive Enhancement)等概念,首先设置核心网页内容,然后随着浏览器/互联网连接的允许,在顶部添加更细致和技术上更严谨的演示层和功能。

有用资源

要了解有关各种提高性能的技术的更多信息,请查看以下资源

  1. 应用 PRPL 模式实现即时加载
  2. 感知性能
  3. 理解关键渲染路径