Back返回博客

Next.js 10

Next.js 10 带来了内置图片优化、国际化路由、Next.js 分析工具、React 17 支持等多项新特性!

我们很高兴推出 Next.js 10,主要特性包括:

内置图片组件与自动图片优化

Next.js 的目标是提升两方面:开发者体验和用户体验。

今年我们已在这两方面投入大量工作,致力于减少浏览器需要加载的 JavaScript 体积。

我们推出了 20 多项新特性 来提升性能和开发者体验,同时 Next.js 核心的 JavaScript 体积 减少了 16%

一月份,我们与 Google Chrome 团队合作推出了业界领先的 JavaScript 代码分割策略。

例如,Barnebys 的应用体积 减少了 23%,Sumup 的最大 JavaScript 包体积 减少了 70%。这些改进 无需修改 Next.js 应用中的任何代码即可实现。

企业只需将 Next.js 升级到最新版本,就能自动获得这些优化。

网络图片现状

虽然我们减少 JavaScript 加载量的努力已见成效,但网络不仅关乎 JavaScript:还包括标记语言和图片。

图片占据了网页总字节数的 50%。

图片对最大内容绘制 (Largest Contentful Paint) 影响重大,因为页面加载时它们通常是最大的可见元素。最大内容绘制是 Google 即将用于搜索排名的 核心网页指标

半数图片大小超过 1MB,这意味着它们并未针对网络展示进行优化。

如今用户使用手机、平板和笔记本浏览网页,但图片仍采用一刀切的方案。例如:网站加载 2000×2000 像素的图片,而手机仅显示为 100×100 像素。

此外,30% 的网页图片位于初始视口之外,意味着浏览器加载了用户需要滚动才能看到的图片。

图片通常缺少 widthheight 属性,导致页面加载时出现布局跳动,影响累积布局偏移 (Cumulative Layout Shift) 这一核心网页指标。

99.7% 的网站图片未使用 WebP 等现代图片格式。

要在网页上高性能地使用图片,需要考虑诸多因素:尺寸、体积、懒加载和现代图片格式。

开发者需要配置复杂的构建工具来优化图片,但这些工具通常无法处理来自外部数据源的用户提交图片,导致无法优化所有图片。

这个不可能完成的任务最终导致了糟糕的终端用户体验。

Next.js 图片组件

我们很高兴宣布针对网络高性能图片的解决方案:Next.js 图片组件与自动图片优化。

本质上,Next.js 图片组件是现代网络环境下 HTML <img> 元素的替代方案。

<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 会根据提供的宽高比自动实现响应式。

开发者可以标记初始视口内的图片,让 Next.js 自动预加载。预加载首屏图片可将最大内容绘制指标提升高达 50%。

自动图片优化

即使相比 HTML <img> 元素有这些改进,仍存在一个主要问题:2000×2000 像素的图片会被发送给仅显示小尺寸图片的手机。

Next.js 10 也解决了这个问题。next/image 组件将通过内置图片优化自动生成更小尺寸。

内置图片优化会自动为支持现代格式的浏览器提供 WebP 等格式(比 JPEG 小约 30%),并能在未来自动适配 新出现的 图片格式。

图片优化适用于任何图片来源,即使来自 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 语言环境标识符,这是定义语言环境的标准格式。

通常语言环境标识符由语言、地区和文字组成,用连字符分隔:语言-地区-文字。地区和文字可选。例如:

  • 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 元标签。更多关于 hreflang 的信息请参阅 Google 站长文档

Next.js 国际化的未来

国际化路由是让项目国际化和本地化更简单的系列功能中的第一个。国际化路由支持与大多数 React 国际化库集成。

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

Next.js 速度分析

在 Vercel,我们深知无法测量就无法改进。

访客对网站性能越来越敏感。超过 50% 的访客 会在网站加载超过 3 秒时离开。电商领域的研究发现,将加载时间缩短 0.1 秒能带来 1% 的转化率提升

由于性能对成功至关重要,我们自豪地发布 Next.js 速度分析。这个解决方案用于跟踪真实世界的性能指标,并将这些洞察反馈到开发工作流中。

使用 Next.js 速度分析:

不再是一次性测量,而是持续测量。

不再是在开发设备上测量,测量数据将来自访客实际使用的设备。

Next.js 速度分析着眼于全局,深入了解您的受众以及应用对用户的表现。

我们坚持收集真实数据,因为性能问题的原因往往并不明显。性能退化可能来自多方面——第三方脚本和样式表,或过大的首方字体、图片和视频。

[注:由于回答长度限制,剩余部分将延续在下一回复中]

核心网页指标 (Core Web Vitals)

Google 与 Web 性能工作组 共同制定了一套指标来准确衡量用户对网站性能的感知体验,这套指标被恰当地命名为 "核心网页指标"。核心网页指标追踪的是网站的可感知加载速度、响应速度以及视觉稳定性——这三者对网站的整体健康状态至关重要!

可感知加载速度可以通过最大内容绘制时间 (Largest Contentful Paint, LCP) 来衡量,即页面所有主要内容显示完成的时间。例如,当我打开一个购买运动鞋的链接时,从点击链接到看到运动鞋图片、价格以及加入购物车按钮之间的时间就是 LCP。

页面响应速度可以通过首次输入延迟 (First Input Delay, FID) 来衡量,它测量用户首次与页面交互后需要等待多久才能看到响应。例如,从我点击 "加入购物车" 到购物车中商品数量增加之间的时间就是 FID。

最后,视觉稳定性可以通过累积布局偏移 (Cumulative Layout Shift, CLS) 来衡量,即元素在显示给用户后移动的程度。例如,我们都经历过试图点击一个因图片延迟加载而移动的按钮时的挫败感——这就是布局偏移。

持续测量并优化这些针对真实用户的核心网页指标至关重要。这是唯一能真正了解网站在用户端表现的方法。网站性能会因用户设备、网络条件或交互方式而有显著差异。加载个性化内容或广告的网站也可能在不同用户间表现出截然不同的性能。

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

Next.js 速度洞察 (Speed Insights) 让您能够获取真实世界的性能数据,而非合成基准测试。它提供持续的测量流,而非依赖偶尔的测试,确保其成为开发者工作流程的一部分。

访问 nextjs.org/analytics 立即了解如何在您的应用中启用此功能。

Next.js 电商解决方案 (Next.js Commerce)

电子商务是互联网最重要的用途之一。Next.js 10 的新特性为电商提供了强大的新工具。

因此,今天我们与 BigCommerce 合作发布了 Next.js Commerce——一个全功能的电商网站 React 启动套件。Next.js 开发者只需点击几下即可克隆、部署并完全自定义它。立即开始使用 nextjs.org/commerce

React 17 支持

React 17 对 Next.js 没有破坏性变更,但需要进行一些维护性更改,例如更新 peer dependencies。当使用 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 快速刷新不会将该函数检测为有效的 React 组件。同样,React hooks eslint 规则也不会将该函数识别为 React 组件。

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

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

getStaticPaths 的阻塞回退

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

在 Next.js 10 中,我们解决了这个问题。

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

pages/posts/[id].js
export function getStaticPaths() {
  return {
    // 为回退行为启用阻塞模式
    fallback: 'blocking',
  };
}

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

getStaticProps / getServerSideProps 的 redirect 和 notFound 支持

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

notFound 支持

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

pages/posts/[id].js
export function getStaticProps() {
  return {
    // 返回默认 404 页面,状态码为 404
    notFound: true,
  };
}

redirect 支持

现在可以返回重定向,其中包含 destination 和重定向是否永久,例如 permanent: true。对于需要使用特定状态码而非默认值的情况,也可以返回可选的 statusCode 来代替 permanent 字段。

pages/posts/[id].js
export function getStaticProps() {
  return {
    // 返回重定向到内部页面 `/another-page`
    redirect: {
      destination: '/another-page',
      permanent: false,
    },
  };
}
pages/posts/[id].js
export function getServerSideProps() {
  return {
    // 返回重定向到外部域名 `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!