跳到内容
返回博客

2020年10月27日,星期二

Next.js 10

发布者

我们很高兴地推出 Next.js 10,其特色功能包括:

内置图像组件和自动图像优化

我们推出 Next.js 的目标是改进两件事:开发者体验和用户体验。

今年,我们已经在开发者体验和改进所有 Next.js 应用程序的性能方面投入了大量资金。我们专注于减少浏览器必须加载的 JavaScript 数量。

我们推出了超过 20 个新功能,这些功能改进了性能和开发者体验。与此同时,Next.js 核心的 JavaScript 大小减少了 16%

一月份,我们与 Google Chrome 团队合作,推出了一项新的、一流的 JavaScript 代码拆分策略。

例如,Barnebys 的应用程序大小减少了 23%,而 Sumup 的最大 Javascript 包大小减少了 70%。这些改进是在不更改其 Next.js 应用程序中的任何代码的情况下实现的。

公司只需将 Next.js 升级到最新版本即可自动采用这项新策略。

Web 上的图像

虽然我们专注于减少浏览器必须加载的 JavaScript 数量已经取得了成效,但 Web 不仅仅是 Javascript:它还包括标记和图像。

图像占 Web 页面总字节数的 50%。

图像对最大内容绘制 (Largest Contentful Paint) 有很大影响,因为它们通常是页面加载时最大的可见元素。最大内容绘制是 Google 将在其搜索排名中使用的核心 Web 指标很快

一半的图像大小超过 1MB,这意味着它们没有针对在 Web 上显示进行优化。

如今,用户使用手机、平板电脑和笔记本电脑浏览 Web,但图像仍然是“一刀切”的。例如:网站加载 2000 x 2000 像素的图像,但手机仅将其显示为 100 x 100 像素。

此外,Web 页面上 30% 的图像在初始视口之外,这意味着浏览器加载了用户向下滚动页面后才看到的图像。

图像通常没有 widthheight 属性,导致页面加载时跳动。这会损害累积布局偏移 (Cumulative Layout Shift) 核心 Web 指标。

网站上 99.7% 的图像未使用现代图像格式,如 WebP。

为了以高性能的方式在 Web 页面上使用图像,必须考虑许多方面:大小、重量、懒加载和现代图像格式。

开发者必须设置复杂的构建工具来优化图像,但是这些工具通常不涵盖来自外部数据源的用户提交的图像,从而无法优化所有图像。

这种不可能的开发任务不可避免地导致令人沮丧的最终用户体验。

Next.js 图像组件

我们很高兴地宣布我们针对 Web 上高性能图像的解决方案:Next.js 图像组件和自动图像优化。

从最基本的角度来看,Next.js 图像组件只是 HTML <img> 元素的直接替代品,专为现代 Web 而进化。

<img
  src="/profile-picture.jpg"
  width="400"
  height="400"
  alt="Profile Picture"
/>
import Image from 'next/image';
<Image
  src="/profile-picture.jpg"
  width="400"
  height="400"
  alt="Profile Picture"
/>;

Google Chrome 团队帮助创建了这个 React 组件,通过将最佳实践设为默认来提高页面性能。

当使用 next/image 组件时,图像会自动懒加载,这意味着它们仅在用户接近看到图像时才呈现。这可以防止加载初始视口之外的 30% 的图像。

图像尺寸是强制执行的,允许浏览器立即渲染图像所需的空间,而不是在加载时跳动,从而防止布局偏移。

虽然 HTML <img> 元素上的 widthheight 可能会导致响应式布局出现问题,但使用 next/image 时并非如此。当使用 next/image 时,图像会根据提供的 widthheight 的宽高比自动变为响应式。

开发者可以标记初始视口中的图像,允许 Next.js 自动预加载这些图像。预加载初始视口中的图像已显示可将最大内容绘制提高多达 50%。

自动图像优化

即使与 HTML <img> 元素相比,这些改进仍然存在一个主要问题。 2000 x 2000 像素的图像被发送到渲染较小图像的手机。

借助 Next.js 10,我们也正在解决这个问题。 next/image 组件将通过内置的图像优化自动生成更小的尺寸。

内置图像优化会自动以现代图像格式(如 WebP)提供图像,如果浏览器支持,WebP 比 JPEG 小约 30%。它还允许 Next.js 自动采用未来的图像格式,并将它们提供给支持这些格式的浏览器。

图像优化适用于任何图像源。即使图像来自外部数据源(如 CMS),也会进行优化。

Next.js 10 不是在构建时优化图像,而是在用户请求时按需优化图像。与静态站点生成器和仅静态解决方案不同,无论您发布 10 个图像还是 1000 万个图像,您的构建时间都不会增加。

结论

新的 next/image 组件和自动图像优化是强大的新基元,将大大改善用户体验。

next/image 组件处理自动懒加载、关键图像的预加载、跨设备的正确尺寸调整,并自动支持现代格式。这些功能适用于来自任何来源的图像。

我们期待看到您的用户体验通过这些新基元变得更快。

有关更多详细信息,请查看 Next.js 图像组件和自动图像优化文档

国际化路由

今年,一些企业和社区成员帮助我们的团队了解了国际化的重要性。

例如,我们了解到,如果您的网站已被翻译,则 72% 的消费者更有可能留在您的网站上,而 55% 的消费者表示他们只从使用其母语的电子商务网站购买商品。

如果您计划在其他国家/地区上市,那么项目的国际化对于成功至关重要。

项目的国际化有两个主要支柱:翻译和路由。

许多 React 库准备了要翻译的应用程序,但它们大多数都希望您手动处理路由,并且通常仅适用于一种渲染策略。

因此,作为 Next.js 10 的一部分,我们发布了对国际化路由和语言检测的内置支持。

这种对国际化路由的内置支持支持 Next.js 的混合策略,因此您可以根据每个页面的情况在静态生成或服务器渲染之间进行选择。

Next.js 10 支持两种最常见的路由策略:子路径路由和域名路由。

对于这两种策略,您首先需要在 Next.js 配置中配置区域设置。

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'nl'],
    defaultLocale: 'en',
  },
};

区域设置是 UTS 区域设置标识符,这是一种用于定义区域设置的标准化格式。

通常,区域设置标识符由语言、区域和脚本组成,并用破折号分隔:language-region-script。区域和脚本是可选的。例如

  • en-US - 美国英语
  • nl-NL - 荷兰荷兰语
  • nl - 荷兰语,无特定区域

配置区域设置后,您可以选择子路径或域名路由。

子路径路由

子路径路由将区域设置放在 URL 中。这允许所有语言都存在于单个域中。

例如,您可以将区域设置插入到 URL 中,例如 /nl-nl/blog/en/blog

域名路由

域名路由使您可以将区域设置映射到顶级域名。例如,example.nl 可以映射到 nl 区域设置,而 example.com 可以映射到 en 区域设置。

域名路由需要一些额外的配置才能知道如何路由域名

next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'nl'],
    domains: [
      {
        domain: 'example.com',
        defaultLocale: 'en',
      },
      {
        domain: 'example.nl',
        defaultLocale: 'nl',
      },
    ],
  },
};

语言检测

Next.js 10 在 / 路由上具有内置的语言检测功能,该功能基于所有现代浏览器都支持的 Accept-Language 标头。配置的区域设置将与 Accept-Language 标头进行匹配,然后根据配置的策略进行重定向。

搜索引擎优化

由于 Next.js 知道用户访问页面的语言,它将自动将 lang 属性添加到 <html> 标记。

Next.js 不知道页面的变体,因此由您使用 next/head 添加 hreflang 元标记。您可以在 Google 网站管理员文档中了解有关 hreflang 的更多信息。

Next.js 中国际化的未来

国际化路由是使您的项目更轻松地进行国际化和本地化的一系列功能中的第一个。国际化路由允许与大多数 React 国际化库集成。

要了解有关国际化路由的更多信息,请查看 国际化路由文档

Next.js Speed Insights

在 Vercel,我们知道您无法修复您无法衡量的事物。

您的访问者对站点性能越来越敏感。如果您的网站加载时间超过 3 秒,超过 50% 的访问者会放弃您的网站如果加载时间超过 3 秒。如果您从事电子商务,许多人发现将加载时间缩短 1/10 秒会导致转化率提高 1%

由于性能对您的成功至关重要,我们很荣幸发布 Next.js Speed Insights。该解决方案用于跟踪真实世界的性能指标,并将这些见解反馈到您的开发工作流程中。

借助 Next.js Speed Insights

您现在将持续衡量,而不是衡量一次。

测量将来自您的访问者正在使用的实际设备,而不是在您的开发设备上进行测量。

Next.js Speed Insights 关注的是整体情况,深入了解您的受众,以及您的应用程序对用户的性能表现。

我们如此坚定地收集真实数据,是因为性能不佳的原因并不总是最明显的。性能下降可能来自各种地方 —— 第三方脚本和样式表,或第一方字体、图像和视频,它们可能过大或速度缓慢。

核心 Web 指标

Google 与 Web 性能工作组 合作,建立了一套指标来准确衡量用户体验网站性能的方式:恰如其名,Web 指标。 Web 指标是跟踪网站的感知加载速度、响应速度和视觉稳定性的指标 —— 这三者对于网站的整体健康状况至关重要!

感知加载速度可以通过最大内容绘制 (Largest Contentful Paint) 或页面所有内容都显示出来的时间来衡量。例如,当我打开一个链接购买一双运动鞋时 —— 在我看到我的运动鞋、价格和添加到购物车按钮之前经过的时间就是 LCP。

页面响应速度可以通过首次输入延迟 (First Input Delay) 来衡量,它衡量用户必须等待多长时间才能看到他们与页面的首次交互的反应。例如,我点击“添加到购物车”和购物车中商品数量增加之间的时间间隔就是 FID。

最终,视觉稳定性可以通过累积布局偏移 (Cumulative Layout Shift) 来衡量,即元素在向用户显示后移动的程度。例如,我们都曾遇到过尝试点击一个按钮,结果按钮却因为图片加载延迟而移动的令人沮丧的情况——这就是布局偏移。

持续地衡量和符合针对真实用户的这些 Web Vitals 指标至关重要。这是真正了解您的网站对用户表现的唯一方法。您网站的性能可能会因用户的设备和网络状况,或者他们与页面的交互方式而差异很大。加载个性化内容或广告的网站也可能因用户而异地体验到截然不同的性能。

模拟测试无法捕捉到这些重要的信号。

Next.js Speed Insights 允许您捕获真实世界的洞察,而不是合成基准。它实现了持续的测量流,而不是依赖于偶尔的测试,从而确保它成为您开发者工作流程的一部分。

Next.js Speed Insights 允许您捕获 真实世界的洞察,而不是合成基准。它实现了 持续的 测量流,而不是依赖于偶尔的测试,从而确保它成为您开发者工作流程的一部分

访问 nextjs.org/analytics 以了解如何立即在您的应用程序中启用它。

Next.js Commerce (电商)

电子商务是 Web 最重要的用途之一。新的 Next.js 10 功能是用于电子商务的强大新工具。

因此,今天,我们与 BigCommerce 合作发布了 Next.js Commerce,这是一个用于电子商务网站的一体化 React 入门套件。只需点击几下,Next.js 开发者就可以克隆、部署和完全自定义它。立即访问 nextjs.org/commerce. 开始使用。

React 17 支持

React 17 对于 Next.js 没有重大更改,但是需要进行一些维护性更改,例如更新对等依赖项。当使用 React 17 时,新的 JSX 转换 会自动启用,无需进行配置更改。

要开始使用 React 17,您只需升级 Next.js 和 React。

终端
npm install next@latest react@latest react-dom@latest

getStaticProps / getServerSideProps 快速刷新

当您编辑 getStaticPropsgetServerSideProps 函数时,Next.js 现在将自动重新运行该函数并应用新数据。这使您可以更快地迭代,而无需刷新页面。

要了解更多关于 getStaticPropsgetServerSideProps 的信息,您可以阅读 数据获取文档

MDX 的快速刷新

当通过 @next/mdx 将 Next.js 与 MDX 结合使用时,更改 MDX 内容现在将利用快速刷新,确保浏览器在编辑时不必重新加载页面。

@next/mdx 文档 指导您完成如何使用 Next.js 设置 MDX。

从第三方 React 组件导入 CSS

您现在可以在 React 组件内部导入第三方 CSS。这允许对仅用于单个组件的 CSS 进行代码拆分。例如,您现在可以使用 react-datepicker 库,而无需在 _app.js 中导入 CSS。

components/MyComponent.js
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
 
function MyComponent() {}

您可以参考 内置 CSS 支持文档,以了解有关 Next.js 如何处理 CSS 导入的更多信息。

自动解析 href

如果您之前使用过动态路由,您可能遇到过需要为 next/link 提供 hrefas 属性的情况。它看起来像这样:

<Link href="/categories/[slug]" as="/categories/books" />

这允许 Next.js 为动态参数插值 href,但是,当开发者忘记添加 as 或在 href 中添加 as 导致页面转换不使用客户端路由时,会造成摩擦。

几个月前,我们着手为开发者解决这种摩擦,主要目标是改善开发者体验和最终用户体验。我们逐步努力寻找一种允许自动解析 href 的解决方案。

我们很高兴地宣布,作为 Next.js 10 的一部分,在大多数用例中您不再需要使用 as 属性。从而减少开发者的摩擦并改善最终用户体验。

此更改是完全向后兼容的,如果您当前同时使用 hrefas,则现有行为将保留。

为了采用自动 href 解析,您只需更改 next/link 的用法,使其仅使用 href,其中包含您之前在 as 属性中拥有的值。

<Link href="/categories/books" />

要了解更多关于 next/link 和客户端路由的信息,您可以参考 next/link 文档

@next/codemod CLI

我们致力于通过广泛的向后兼容性,确保 Next.js 升级尽可能顺利。这项承诺始于非常谨慎地弃用功能,同时引入新的和更好的解决方案来替代它们。除了这项承诺之外,我们还对所有 Next.js 功能进行了广泛的集成测试,包括复制本地开发的测试。

当 Next.js 中的某个功能被弃用并需要大量代码库更改时,我们的团队会为其创建 codemod。Codemod 是一种自动化代码转换,您可以在项目上运行它来更新源代码。

例如:我们发布了一个 codemod,用于将箭头函数和匿名函数更新为命名函数。此转换 是必需的,因为否则 React Fast Refresh 不会将该函数检测为有效的 React 组件。同样,React hooks eslint 规则也不会将该函数识别为 React 组件。

在 Next.js 10 中,我们发布了一个新的 Next.js codemods CLI 工具,允许您运行单个命令来更新您的应用程序:npx @next/codemod <transform> <path>

要了解更多关于 codemods 的信息,您可以查看 Next.js Codemods 文档

getStaticPaths 的阻塞式回退 (Blocking Fallback)

在 Next.js 9.3 中,我们引入了 getStaticPropsgetStaticPaths,以及在 getStaticPaths 中返回 fallback 属性的功能。fallback 属性允许生成额外的静态页面,而无需完全重建,最初提供一个静态 HTML 文件,然后在后续请求中被完全渲染的内容替换。在过去的几个月中,我们收到了许多公司的反馈,他们想要一种类似但略有不同的行为:当用户首次请求页面时进行阻塞式预渲染。在初始渲染之后,该页面将被重用于后续请求。

在 Next.js 10 中,我们正在解决这种情况。

我们很高兴地宣布 getStaticPaths 的新 fallback: 'blocking' 模式,该模式启用了阻塞行为,其中没有静态回退发送到浏览器。相反,初始请求会等待预渲染完成。

pages/posts/[id].js
export function getStaticPaths() {
  return {
    // enables blocking mode for the fallback behavior
    fallback: 'blocking',
  };
}

要了解更多关于增量生成额外静态页面的 fallback 行为的信息,您可以参考 fallback 文档

getStaticProps / getServerSideProps 的重定向和 notFound 支持

自从引入 getStaticPropsgetServerSideProps 以来,我们注意到用户需要在某些情况下返回重定向和 404 响应。为了简化这些情况,我们现在允许从 getStaticPropsgetServerSideProps 返回两个新字段:notFoundredirect

notFound 支持

当返回 notFound 字段并设置为 true 时,将返回默认的 404 页面,状态代码为 404。这使您可以避免使用 SSG 生成额外的页面,并且无需手动处理 404 页面的渲染。

pages/posts/[id].js
export function getStaticProps() {
  return {
    // returns the default 404 page with a status code of 404
    notFound: true,
  };
}

redirect 支持

现在可以返回重定向,其中包含 destination 以及重定向是否应为永久性,例如 permanent: true。在需要使用特定状态而不是默认状态的情况下,也可以返回可选的 statusCode 来代替 permanent 字段。

pages/posts/[id].js
export function getStaticProps() {
  return {
    // returns a redirect to an internal page `/another-page`
    redirect: {
      destination: '/another-page',
      permanent: false,
    },
  };
}
pages/posts/[id].js
export function getServerSideProps() {
  return {
    // returns a redirect to an external domain `example.com`
    redirect: {
      destination: 'https://example.com',
      permanent: false,
    },
  };
}

结论

我们很高兴看到 Next.js 的采用持续增长。

  • 我们已经有超过 1,300 位独立贡献者,自 9.5 版本发布以来新增超过 120 位贡献者。
  • 在 GitHub 上,该项目已被标星超过 54,800 次。

加入 Next.js 社区,请访问 GitHub Discussions。 Discussions 是一个社区空间,您可以在其中与其他 Next.js 用户联系,并自由提问或分享您的工作。

鸣谢

我们感谢我们的社区,包括所有帮助塑造此版本的外部反馈和贡献。

此版本由以下贡献者共同完成:@ijjk, @adebiyial, @elliottsj, @saintmalik, @HaNdTriX, @prateekbh, @amirsaeed671, @paambaati, @imagentleman, @gregrickaby, @Janpot, @atcastle, @Kirkhammetz, @remorses, @davidsonsns, @kmkzt, @slawekkolodziej, @Timer, @styfle, @timneutkens, @ykzts, @ashconnell, @orYoffe, @lfades, @justinwhall, @fbaiodias, @ludofischer, @felipeguilhermefs, @gr-qft, @TasukuUno, @YichiZ, @weichienhung, @seosmmbusiness, @HsuTing, @gsimone, @peduarte, @ztanner, @neighborhood999, @chibicode, @merceyz, @opudalo, @lunchboxav, @mohsen1, @akd-io, @justman00, @helloworld, @devknoll, @borekb, @ArthurMaverick, @sakito21, @TrySound, @omBratteng, @svenheden, @hallaji, @kettanaito, @vvo, @m-lautenbach, @jensmeindertsma, @Zeko369, @longlho, @stefanprobst, @laugharn, @sdornan, @daneroo, @mohd-akram, @austingmhuang, @sphilee, @devinekadeni, @Bacher, @nghiepit, @tomasdisk, @leader22, @paulogdm, @284km, @belgattitude, @geritol, @stigkj, @sampoder, @samrobbins85, @Pitasi, @digitalPlayer1125, @timfee, @plug-n-play, @philihp, @leerob, @dylanjha, @Kerumen, @rdimaio, @jorisw, @zerbinidamata, @jamesgeorge007, @Jashnm 和 @futantan!