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: true,
          visibility: false,
        },
      },
    },
  },
})
阅读更多关于 NuxtLink

混合渲染

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

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

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

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

阅读更多关于 混合渲染

组件懒加载

要动态导入组件(也称为懒加载组件),你所需做的就是在组件名称前加上 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 bundle 大小。

阅读更多关于 组件懒加载

懒水合

在初始加载时,没必要对网站的所有组件进行水合(或使其具有交互性)。通过使用懒水合,你可以控制何时加载组件的代码,这可以改善应用的首次可交互时间指标。Nuxt 允许你通过懒水合来控制组件何时变为可交互状态(于 Nuxt v3.16 引入)。

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

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

阅读更多关于 懒水合

数据获取

为了避免获取相同的数据两次(一次在服务器上,一次在客户端),Nuxt 提供了 useFetchuseAsyncData。它们确保如果在服务器上进行了 API 调用,数据会包含在有效负载(payload)中转发给客户端,而不会再次被获取。

阅读更多关于 数据获取

Nuxt 核心模块

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

图片

未优化的图片会对你的网站性能产生显著的负面影响,特别是 最大内容绘制 (LCP) 得分。

在 Nuxt 中,我们可以使用 Nuxt Image 模块,这是一个针对 Nuxt 应用的即插即用图片优化工具。它允许使用内置优化器或你喜欢的图片 CDN 来调整图片大小和进行转换。

<NuxtImg> 是原生 <img> 标签的无缝替代品,附带以下增强功能

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

你网站中的图片通常可以按重要性分类:初次加载时需要优先交付的图片(即 Largest Contentful Paint),以及可以稍后加载或在特定需要时加载的图片。为此,我们可以使用以下优化方法

<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 将自动优化你的字体(包括自定义字体)并移除外部网络请求,以提高隐私性和性能。

它为任何字体文件内置了自动自托管功能,这意味着借助底层包 fontaine,你可以以更小的布局偏移量优化加载 Web 字体。

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

nuxt 命令允许你分析 Nuxt 应用的生产包。它利用 vite-bundle-visualizer(类似于 webpack-bundle-analyzer)来生成应用打包结果的可视化图表,从而更轻松地识别出哪些组件占用的空间最大。

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

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

Nuxt DevTools

Nuxt DevTools 为你提供有关 Nuxt 应用的深入见解和透明度,以识别性能差距并无缝管理你的应用配置。

它附带了几项可用于衡量 Nuxt 应用性能的功能

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

Chrome DevTools

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

当你打开 Performance 面板时,它会立即显示你的本地 最大内容绘制 (LCP)累积布局偏移 (CLS) 得分(良好、需要改进或差)。

如果你与页面进行交互,它还会捕获 交互到下一次绘制 (INP),从而根据你的设备和网络为你提供核心网页指标的全景视图。

Lighthouse 对性能、无障碍性、SEO、渐进式 Web 应用和最佳实践进行审计。它在你的页面上运行测试并生成报告。将未通过的审计项目作为改进网站的指南。

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

PageSpeed Insights

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

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

Web Page Test

WebPageTest 是一个网页性能工具,提供关于页面在各种条件下的性能表现的深度诊断信息。

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

常见问题

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

过度使用插件

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

解决方案:检查你的插件,看看其中是否有某些插件可以改用组合式函数或工具函数来实现。

未使用的代码 / 依赖项

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

解决方案:检查你的 package.json 以查找未使用的依赖项,并分析代码中未使用的 utils/composables/functions。

未利用 Vue 性能优化建议

问题Vue 文档 列出了几项我们也可以在 Nuxt 项目中使用的性能改进措施,但由于它们是 Vue 文档的一部分,开发人员往往会忽视它们,而只关注 Nuxt 特定的改进——尽管 Nuxt 应用本质上仍然是一个 Vue 项目。

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

未遵循规范

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

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

试图同时加载所有内容

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

解决方案:使用诸如渐进式增强(Progressive Enhancement)之类的概念,即首先设置网页核心内容,然后根据浏览器/互联网连接允许的情况,在上面添加更精细、技术要求更高的呈现层和功能。

有用的资源

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

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