有兴趣了解我们的下一本书?了解更多关于 使用 React 构建大规模 JavaScript Web 应用程序

优化 Next.js 应用程序以实现核心 Web 指标

优化针对 核心 Web 指标 的用户体验涉及提高页面速度、交互性和视觉稳定性。使用 Next.js,有几个组件与 Chrome 团队 合作构建,可以帮助改进核心 Web 指标指标。

  • next/imagenext/image 组件是一个优化的图像组件,可以通过调整大小、压缩和延迟加载来自动优化图像,以实现更好的 最大内容绘制 (LCP) 和 累积布局偏移 (CLS)。它还可以用来显示适应不同屏幕尺寸的响应式图像。

  • next/scriptnext/script 组件可用于异步加载第三方脚本,以提高页面速度和交互性。它还可以用来延迟加载非关键脚本(如分析脚本),以防止它们减慢初始页面加载速度。这些技术可以改善诸如 首次输入延迟 (FID) 和 交互到下一绘制 (INP) 之类的指标。

  • next/fontnext/font 组件可用于优化 Web 字体加载,通过异步加载字体并优先考虑初始页面加载的最重要字体样式。这可以通过防止由字体加载引起的布局偏移 (CLS) 来帮助提高页面速度和视觉稳定性。

让我们详细了解每个组件的功能。

Next.js 图像组件

Next.js 图像组件,next/image,是 HTML <img> 元素的扩展:它提供性能优化,以帮助你实现良好的 核心 Web 指标。这些分数是衡量用户体验你网站的效果的重要指标,并且会影响 Google 的搜索排名。

官方 Next.js 文档

内置优化

图像组件中内置的一些优化包括

  • 性能改进:始终为每个设备提供正确尺寸的图像,使用现代图像格式
  • 视觉稳定性:自动防止 累积布局偏移 更快的页面加载速度:图像仅在进入视窗时才会加载,并提供可选的模糊占位符
  • 资产灵活性:按需图像调整大小,即使对于存储在远程服务器上的图像也是如此 使用图像组件

要将图像添加到你的应用程序,请导入 next/image 组件

import Image from "next/image";

现在,你可以为你的图像定义 src(本地或远程)。

本地图像 要使用本地图像,请导入你的 .jpg、.png 或 .webp 文件

import profilePic from "../public/me.png";

导入必须是静态的,以便在构建时进行分析。

Next.js 将根据导入的文件自动确定图像的宽度和高度。这些值用于在图像加载时防止累积布局偏移。

import Image from "next/image";
import profilePic from "../public/me.png";

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src={profilePic}
        alt="Picture of the author"
        // width={500} automatically provided
        // height={500} automatically provided
        // blurDataURL="data:..." automatically provided
        // placeholder="blur" // Optional blur-up while loading
      />
      <p>Welcome to my homepage!</p>
    </>
  );
}

远程图像

要使用远程图像,src 属性应为 URL 字符串,可以是相对的或绝对的。因为 Next.js 在构建过程中无法访问远程文件,所以你需要手动提供 width、height 和可选的 blurDataURL 属性

import Image from "next/image";

export default function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        src="/me.png"
        alt="Picture of the author"
        width={500}
        height={500}
      />
      <p>Welcome to my homepage!</p>
    </>
  );
}

域名

有时你可能希望优化远程图像,但仍然使用内置的 Next.js 图像优化 API。为此,请将加载程序保留在默认设置,并为图像 src 属性输入绝对 URL。

为了保护你的应用程序免受恶意用户的影响,你必须定义一个打算与 next/image 组件一起使用的远程主机名列表。

加载程序 请注意,在前面的示例中,为远程图像提供了一个部分 URL(“/me.png”)。这是因为加载程序架构的原因。

加载程序是一个生成图像 URL 的函数。它会修改提供的 src,并生成多个 URL 以请求不同尺寸的图像。这些多个 URL

带自动大小的远程图像

如果你使用的是远程图像,则需要为图像组件提供 width 和 height 属性。但是,如果你不确定远程图像的尺寸,可以使用 layout 属性和 aspectRatio 属性的组合让 Next.js 自动计算宽度和高度。

例如,如果你想显示一个 16:9 长宽比的远程图像,并且希望图像组件填充其容器,可以使用以下代码

import Image from "next/image";

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <div style={{ width: "100%", height: "50vh" }}>
        <Image
          src="https://example.com/my-image.jpg"
          alt="My Image"
          layout="fill"
          objectFit="cover"
          aspectRatio={16 / 9}
        />
      </div>
      <p>Welcome to my homepage!</p>
    </>
  );
}

在此示例中,layout 属性设置为 fill,这告诉 Next.js 填充父容器的尺寸。objectFit 属性设置为 cover,这会缩放图像以覆盖整个容器,同时保留其长宽比。aspectRatio 属性设置为 16 / 9,这是图像的长宽比。

自定义加载程序

默认情况下,Next.js 使用内置的图像优化 API 来优化和提供图像。但是,如果你想从其他来源(如 CDN 或图像服务器)提供图像,可以定义一个自定义加载程序函数。

加载程序函数是一个生成图像 URL 的函数。它接受一个 src 参数,该参数是图像的源 URL,并返回一个具有以下属性的对象

  • src:原始图像的 URL。
  • width:图像的宽度。
  • height:图像的高度。
  • blurDataURL:表示图像模糊版本的 base64 编码字符串。这用作图像加载时的占位符。

以下是一个自定义加载程序函数的示例,它生成存储在 AWS S3 上的图像的 URL

import Image from "next/image";

function myLoader({ src, width, quality }) {
  return `https://example.com/images/${src}?w=${width}&q=${quality || 75}`;
}

function Home() {
  return (
    <>
      <h1>My Homepage</h1>
      <Image
        loader={myLoader}
        src="my-image.jpg"
        alt="My Image"
        width={500}
        height={500}
      />
      <p>Welcome to my homepage!</p>
    </>
  );
}

在此示例中,loader 属性设置为 myLoader,它是一个自定义加载程序函数,用于生成存储在 AWS S3 上的图像的 URL。src 属性设置为 my-image.jpg,这是图像文件的名称。width 和 height 属性设置为 500,这是图像的大小。

结论

总之,Next.js 图像组件是优化 Next.js 应用程序中图像的强大工具。它包括各种内置的性能优化,以帮助你实现良好的核心 Web 指标,例如性能改进、视觉稳定性、更快的页面加载速度和资产灵活性。

你可以使用图像组件将本地或远程图像添加到你的应用程序,Next.js 将自动确定图像的宽度和高度,以防止在图像加载时出现累积布局偏移。你还可以使用自定义加载程序。

Next.js 脚本组件

官方文档

第三方脚本是开发人员节省时间并利用现有解决方案来实现常见功能的一种常见方法。但是,这些脚本的创建者通常会忽略其代码对使用它们的网站的性能影响,从而导致用户体验不佳。这些脚本也给开发人员带来了挑战,他们可能不知道如何优化其性能。

脚本代表了网站跨不同类别第三方请求下载的相当数量的第三方字节。默认情况下,浏览器会根据脚本在文档中的位置来优先考虑脚本,这可能会延迟发现或执行对用户体验至关重要的脚本。布局所需的第三方库应尽早加载以渲染页面,而非关键的第三方应延迟加载,以防止它们阻塞主线程上的其他处理。Lighthouse 有两个审核来标记渲染阻塞或主线程阻塞脚本。务必考虑页面的资源加载顺序,以便不延迟关键资源,并且非关键资源不阻塞关键资源。

为了解决这些问题,Next.js 开发了一个脚本组件,该组件封装了排序功能,为开发人员提供了对第三方脚本加载的更好控制。该组件实现了有效加载和排序第三方脚本的方法,并为开发人员提供了一个模板来定义其加载策略。一旦指定了合适的策略,它将以最佳方式加载,而不会阻塞其他关键资源。

在讨论 Next.js 脚本组件之前,让我们看一下可用的指南,以减少渲染阻塞脚本的影响。

有效加载和排序第三方脚本的方法

可用的指南提供了以下方法,用于有效加载和排序第三方脚本

使用 <script> 标记中的 async 或 defer 属性,告诉浏览器加载非关键的第三方脚本,而不阻塞文档解析器。对于初始页面加载或首次用户交互不需要的脚本,可以考虑为非关键脚本。

<script src="https://example.com/script1.js" defer></script>
<script src="https://example.com/script2.js" async></script>
Establish early connections to required origins using preconnect and
dns-prefetch. This allows critical scripts to start downloading earlier.

<head>
  <link rel="preconnect" href="http://PreconnThis.com" />
  <link rel="dns-prefetch" href="http://PrefetchThis.com" />
</head>

延迟加载第三方资源和嵌入,在主页面内容加载完毕或用户向下滚动到包含它们的页面部分后进行加载。

Next.js 脚本组件

Next.js 脚本组件基于 HTML <script> 标记,并提供了一个选项,可以使用 strategy 属性设置第三方脚本的加载优先级。一旦指定了合适的策略,它将以最佳方式加载,而不会阻塞其他关键资源。

// Example for beforeInteractive:

<script
  src="https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserverEntry%2CIntersectionObserver"
  strategy="beforeInteractive"
/>

// Example for afterInteractive (default):
<script src="https://example.com/samplescript.js" />

// Example for lazyonload:
<script src="https://connect.facebook.net/en_US/sdk.js" strategy="lazyOnload" />

strategy 属性可以采用三个值

  1. beforeInteractive:此选项可用于在页面变得可交互之前应执行的关键脚本。Next.js 确保在服务器上将此类脚本注入初始 HTML,并在其他自捆绑的 JavaScript 之前执行。同意管理、机器人检测脚本或渲染关键内容所需的辅助库是此策略的良好候选者。

  2. afterInteractive:这是应用的默认策略,等效于使用 defer 属性加载脚本。

  3. lazyOnloadExternal: 此选项可用于在浏览器空闲时加载来自外部服务器的低优先级脚本。此策略在脚本对渲染页面不重要且可以在页面初始加载后加载时特别有用。一个示例是广告脚本,它们可以在用户空闲时在页面初始加载后加载。

Script 组件还提供了一种机制,可以使用 inline 属性内联第三方脚本。内联脚本可以帮助减少网站发出的请求数量,这对于小型脚本特别有用。但是,不建议内联大型脚本,因为它们会增加 HTML 文档的大小,从而使其下载速度变慢。

// Example for inlining a script:

<script inline src="https://example.com/inlinescript.js" />

除了上述内容之外,Script 组件还提供其他功能,例如脚本缓存、脚本去重和脚本回退。缓存脚本可以帮助提高页面加载速度,尤其是在用户重新访问网站时。对脚本进行去重可以帮助减少对服务器发出的请求数量,从而减轻服务器负担。最后,脚本回退可用于在主脚本加载失败时加载不同的脚本。

Next.js 字体组件

优化字体回退对于 Web 性能和可访问性至关重要。当用户访问网站时,他们应该能够尽快看到内容,即使网站使用的自定义字体尚未加载。在本文中,我们将探讨 Next.js 字体组件及其如何帮助优化字体回退。

Next.js 提供了一种内置方式来启用回退字体优化。当您使用 @next/font 组件加载字体时,默认情况下会启用此功能。@next/font 组件是在 Next.js 13 版本中引入的,它提供了一个 API 来将 Google 字体或自定义字体导入您的页面。它还包括内置的自动自托管字体文件。

使用时,回退字体指标会自动计算并注入到 CSS 文件中。这确保了当自定义字体不可用时,回退字体在大小和行高方面将与自定义字体匹配。这可以防止在加载回退字体时可能发生的任何布局偏移。

使用 Next.js 字体组件

假设您正在使用 Roboto 字体。通常,您将在 CSS 中定义它,如下所示

@font-face {
  font-family: "Roboto";
  font-display: swap;
  src: url("/fonts/Roboto.woff2") format("woff2"), url("/fonts/Roboto.woff")
      format("woff");
  font-weight: 700;
}

body {
  font-family: Roboto;
}

要迁移到 Next.js 字体组件,请通过从 'next/font' 导入 'Roboto' 函数将 Roboto 字体声明移至您的 JavaScript 中。该函数的返回值将是您可以在组件模板中使用的类名。请记住将 display: swap 添加到配置对象以启用此功能。

import { Roboto } from "@next/font/google";

const roboto = Roboto({
  weight: "400",
  subsets: ["latin"],
  display: "swap", // Using display swap automatically enables the feature
});

在您的组件中,使用生成的类名

export default function RootLayout({
  children,
}: {
  children: React.ReactNode,
}) {
  return (
    <html lang="en" className={roboto.className}>
      <body>{children}</body>
    </html>
  );
}

请注意,Next.js 字体组件设计为仅支持 'Arial' 和 'Times New Roman' 作为回退字体。做出此选择的主要原因是 Arial 和 Times New Roman 字体在跨平台上的普遍支持。

adjustFontFallback 配置选项

Next.js 字体组件有一个 adjustFontFallback 配置选项,可用于启用或禁用自动字体回退。对于 @next/font/google,这是一个布尔值,用于设置是否应使用自动回退字体以减少累积布局偏移。默认值为 true。Next.js 会自动将您的回退字体设置为 Arial 或 Times New Roman,具体取决于字体类型(分别为衬线或无衬线)。

对于 @next/font/local,这是一个字符串或布尔值 false,用于设置是否应使用自动回退字体以减少累积布局偏移。可能的值为 Arial、Times New Roman 或 false。默认值为 Arial。如果要使用衬线字体,请考虑将此值设置为 Times New Roman。

优化 Google 字体

如果无法使用 Next.js 字体组件,则另一种使用此功能的 Google 字体的方法是通过 optimizeFonts 标志。Next.js 默认情况下已启用 optimizeFonts 功能。此功能会将 Google 字体 CSS 内联到 HTML 响应中。此外,您可以通过在 next 中设置 experimental.adjustFontFallbacksWithSizeAdjust 标志来启用字体回退调整功能

使用 @next/font 组件,您也可以将自定义字体导入您的页面。要使用自定义字体,首先需要将您的字体文件上传到公共目录。然后,您可以使用 @font-face CSS 规则来定义您的字体系列和来源。

以下是如何使用 @next/font 组件使用自定义字体的示例

// In your component
import { MyCustomFont } from "@next/font/local";

const myCustomFont = MyCustomFont({
  weight: "normal",
  src: 'url("/fonts/MyCustomFont.woff2") format("woff2")',
});

export default function MyComponent() {
  return (
    <div className={myCustomFont.className}>
      <h1>Hello World</h1>
    </div>
  );
}
// In your CSS
@font-face {
  font-family: "MyCustomFont";
  font-weight: normal;
  src: url("/fonts/MyCustomFont.woff2") format("woff2");
}

使用 @next/font 组件,您还可以通过仅加载页面上需要的字体来优化字体加载。为此,您可以使用 Font Observer API 来检测页面何时需要字体并动态加载它。

以下是如何使用 @next/font 组件使用 Font Observer API 的示例

// In your component
import { useFontObserver } from "@next/font";

export default function MyComponent() {
  const [isFontReady, fontClassName] = useFontObserver("Inter", {
    weight: "400",
    subsets: ["latin"],
  });

  return (
    <div className={fontClassName}>
      {isFontReady ? (
        <h1>Hello World</h1>
      ) : (
        <h1 style={{ fontFamily: "sans-serif" }}>Hello World</h1>
      )}
    </div>
  );
}

在此示例中,useFontObserver 钩子用于检测页面何时需要重量为 400 且具有拉丁语子集的 'Inter' 字体。该钩子返回一个布尔值,指示字体是否已准备好使用,以及一个可以应用于您的组件的字体类名。

如果字体尚未准备好,该组件将使用 fontFamily CSS 属性显示回退字体。字体准备就绪后,该组件将使用 'Inter' 字体显示文本。

总之,@next/font 组件提供了一种简单的方法来优化 Next.js 应用程序中的字体回退。通过使用此组件,您可以通过仅加载必要的字体并减少字体加载造成的累积布局偏移来提高 Web 应用程序的性能和用户体验。

总结

next/imagenext/scriptnext/font 可以对改进核心 Web 指标产生重大影响。如果您正在构建 Next.js 应用程序,并且希望确保它具有良好的用户体验,请考虑利用它们。