跳至内容
返回博客

2020年7月27日,星期一

Next.js 9.5

发布者

我们很高兴今天推出 Next.js 9.5,其特性包括

稳定的增量静态重生成

Next.js 在 9.3 版本中引入了静态网站生成方法,目标明确:我们应该获得 静态的好处(始终快速,始终在线,全局复制),同时对 Next.js 闻名的动态数据提供出色的支持。

为了兼得两全其美,Next.js 引入了 **增量静态生成**,在您已经构建网站之后更新静态内容。通过使用 getStaticPaths 中的 fallback: true 选项,您可以 **在运行时注册新的静态页面**。

Next.js 可以通过这种方式按需静态预渲染无限数量的页面,无论您的数据集有多大。

今天,我们宣布 **增量静态重生成** 的正式发布,这是一种 **更新现有页面** 的机制,通过在后台重新渲染它们,并在流量进入时进行处理。

stale-while-revalidate 的启发,后台重生成确保流量始终从静态存储中无中断地提供服务,并且新构建的页面仅在生成完成后才推送。

export async function getStaticProps() {
  return {
    props: await getDataFromCMS(),
    // we will attempt to re-generate the page:
    // - when a request comes in
    // - at most once every second
    revalidate: 1,
  };
}

revalidate 标志是在最多发生一次生成期间的秒数,以防止 https://en.wikipedia.org/wiki/Cache_stampede

与传统的 SSR 不同,增量静态重生成确保您保留静态的好处

  • 延迟不会出现峰值。页面始终以很快的速度提供服务。
  • 页面永远不会离线。如果后台页面重生成失败,旧页面将保持不变。
  • 数据库和后端负载低。页面最多同时重新计算一次。

增量功能(添加页面并延迟更新),以及 预览模式,现在都已稳定并得到 next startVercel 边缘平台 的开箱即用支持。

为了展示此新功能,我们创建了一个示例,展示了如何重新生成一个静态页面,该页面显示特定问题的各种 GitHub 反应计数:https://reactions-demo.vercel.app/

After the first visit following our emoji reaction, a new page generation kicks off in the background. Every single request throughout is served from static cache.
在第一次访问并进行表情符号反应后,一个新的页面生成将在后台启动。整个过程中的每个请求都将从静态缓存中提供服务。

接下来,我们将着手撰写补充 RFC,以解决增量静态生成的其他两种功能。

  • 一次重新生成和失效多个页面(例如您的博客索引和某个博客文章)
  • 通过监听事件(例如 CMS Webhook)在用户流量到来之前重新生成

有关更多详细信息,请查看 getStaticProps 文档

可自定义的基础路径

Next.js 项目并不总是从域的根目录提供服务。有时您可能希望在子路径(例如 /docs)下托管您的 Next.js 项目,以便 Next.js 项目仅覆盖域的该子部分。

虽然到目前为止这已经成为可能,但它需要付出相当多的额外配置。例如,为每个 <Link> 添加前缀,并确保 Next.js 从正确的路径提供 JavaScript 包。

为了解决这个痛点,我们引入了一个新的配置选项。basePath 允许您轻松地在域的子路径上托管您的 Next.js 项目。

要开始使用 basePath,您可以将其添加到 next.config.js

next.config.js
module.exports = {
  basePath: '/docs',
};

配置 basePath 后,您的项目将自动从提供的路径路由。在本例中为 /docs

当使用 next/linknext/router 链接到项目中的其他页面时,basePath 将自动添加前缀。这允许您更改 basePath 而不必更改您的项目。

例如,使用 next/link 路由到另一个页面

import Link from 'next/link';
 
export default function HomePage() {
  return (
    <>
      <Link href="/documentation-page">
        <a>Documentation page</a>
      </Link>
    </>
  );
}

以这种方式使用 next/link 将导致以下 HTML 呈现到 Web 浏览器中

<a href="/docs/documentation-page">Documentation page</a>

有关更多详细信息,请查看 basePath 文档

对重写、重定向和标头的支持

重写

在构建 Next.js 项目时,您可能希望将某些路由代理到另一个 URL。例如,如果您希望将 Next.js 增量地引入您的堆栈中,您将希望路由存在于 Next.js 项目中的页面,然后将所有未匹配到您正在迁移出的旧项目的页面路由到旧项目。

在 Next.js 9.5 中,我们引入了一个名为 rewrites 的新配置选项,它允许您将传入的请求路径映射到不同的目标路径,包括外部 URL。

例如,您可能希望将某个路由重写到 example.com

next.config.js
module.exports = {
  async rewrites() {
    return [
      { source: '/backend/:path*', destination: 'https://example.com/:path*' },
    ];
  },
};

在本例中,/backend 下的所有路径都将路由到 example.com

您还可以检查您的 Next.js 项目路由是否匹配,然后如果未匹配则重写到之前的项目。这对于 **Next.js 的增量采用** 非常有用

module.exports = {
  async rewrites() {
    return [
      // check if Next.js project routes match before we attempt proxying
      {
        source: '/:path*',
        destination: '/:path*',
      },
      {
        source: '/:path*',
        destination: `https://example.com/:path*`,
      },
    ];
  },
};

在本例中,我们首先匹配所有路径。如果没有任何匹配,我们将代理到 example.com,这将是之前的项目。

要了解有关 rewrites 功能的更多信息,请查看 rewrites 文档

重定向

大多数网站至少需要一些重定向。尤其是在更改项目路由结构时。例如,当将 /blog 移动到 /news 或类似的转换时。

以前,在 Next.js 项目中拥有重定向列表需要设置自定义服务器或自定义 _error 页面来检查路由是否设置了重定向。但是,这以使关键的静态和无服务器优化失效(通过使用服务器)或不够符合人体工程学为代价。

从 Next.js 9.5 开始,您现在可以在 next.config.js 中的 redirects 键下创建重定向列表

next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
    ];
  },
};

要了解有关 redirects 功能的更多信息,请查看 redirects 文档

标头

Next.js 允许您构建使用静态生成和服务器端渲染的混合项目。使用服务器端渲染,您可以为传入请求设置标头。对于静态页面,直到现在才无法设置标头。

我们现在在 next.config.js 中引入了 headers 属性,该属性适用于所有 Next.js 路由

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Feature-Policy',
            // Disable microphone and geolocation
            value: "microphone 'none'; geolocation 'none'",
          },
        ],
      },
    ];
  },
};

headers 选项允许您设置常用的标头,例如 Feature-PolicyContent-Security-Policy

要了解有关 headers 功能的更多信息,请查看 headers 文档

URL 中可选的后缀斜杠

3 年前推出 Next.js 时,其默认行为是所有带有后缀斜杠的 URL 始终返回 404 页面。

虽然有效,但一些用户已请求更改此行为。例如,当将现有项目迁移到以前始终强制使用后缀斜杠的 Next.js 时。

在 Next.js 9.5 中,我们为 next.config.js 引入了一个名为 trailingSlash 的新选项。

此新选项确保 Next.js 自动处理后缀斜杠行为

  • 自动将带有后缀斜杠的 URL 重定向到没有后缀斜杠的 URL,例如:/about/ 重定向到 /about
  • trailingSlash 设置为 true 时,将把没有后缀斜杠的 URL 重定向到带有后缀斜杠的 URL,例如:/about 重定向到 /about/
  • 确保 next/link 自动应用/删除后缀斜杠,以避免不必要的重定向。
next.config.js
module.exports = {
  // Force a trailing slash, the default value is no trailing slash (false)
  trailingSlash: true,
};

要了解有关 trailingSlash 功能的更多信息,请查看 trailingSlash 文档

页面包的持久缓存

在编写 Next.js 页面时,所有脚本包、CSS 样式表和 HTML 的创建都是完全自动的,并且对您来说是抽象的。如果您在 Next.js 9.5 之前检查生成的 <script> 标签,您会注意到它们的 URL 遵循以下模式

/_next/static/ovgxWYrvKyjnlM15qtz7h/pages/about.js

上面的路径段 ovgxWYrvKyjnlM15qtz7h 是我们所说的构建 ID。虽然这些文件很容易在边缘和用户机器上进行缓存,但在重新构建应用程序后,构建 ID 会发生变化,并且所有缓存都将失效。

对于大多数项目来说,这种权衡是可以接受的,但是,我们希望通过不再使浏览器缓存失效(对于未更改的页面)来进一步优化此行为。

在与 Google Chrome 团队合作开发的 Next.js 9.2 中改进的代码拆分策略 中引入了这些改进,为 Next.js 页面包生成奠定了基础。

从 Next.js 9.5 开始,**所有页面 JavaScript 包都将使用内容哈希而不是构建 ID**。这允许在部署之间没有更改的页面保留在浏览器和边缘缓存中,而无需再次下载。

相反,这些更改后的 URL 模式如下所示

/_next/static/chunks/pages/about.qzfS4o5gIEXRME6sTEahL.js

取代全局构建 ID,qzfS4o5gIEXRME6sTEahL 部分是 about.js bundle 的确定性哈希值,只要您网站该部分的代码没有更改,它就会保持稳定。此外,**它现在通过 `Cache-Control: public,max-age=31536000,immutable` 在重新部署之间进行长期缓存**,Next.js 会自动为您设置。

快速刷新增强

我们在 Next.js 9.4 中引入了快速刷新,这是一种新的热重载体验,可以为您对 React 组件所做的编辑提供即时反馈。

Next.js 9.5 进一步完善了我们的快速刷新实现,并为您提供了取得成功的工具。

  • **易于理解的错误**:所有编译和运行时错误都已更新为 仅显示**相关信息,包括导致错误的代码片段**
  • **保持组件状态的开发时提示**:Next.js 现在为您提供了有用的提示,以确保快速刷新在尽可能多的情况下保持您的组件状态。Next.js 提供的每个提示都是**完全可操作的**,并附带前后示例!
  • **组件状态重置时的警告**:当 Next.js 无法在编辑文件后保持组件状态时,我们现在会打印详细的警告。此警告将帮助您诊断项目必须重置组件状态的原因,从而允许您修复它并充分利用快速刷新。
  • **新的文档**:我们已 添加了大量文档,解释了快速刷新是什么、它是如何工作的以及可以期待什么!文档还将通过解释其错误恢复工作原理来教您如何更好地利用快速刷新。
  • **用户代码故障排除指南**:新文档还包括 常见的故障排除步骤和技巧,关于如何在开发中充分利用快速刷新。

生产环境 React 性能分析

React 之前引入过 Profiler API,它允许您追踪 React 组件中的性能问题。虽然此功能在开发环境中自动工作,但它需要使用单独版本的 ReactDOM 才能在生产环境中进行性能分析。

使用 Next.js 9.5,您现在可以使用 `next build` 中的 `--profile` 标志**启用 React 的生产环境性能分析**。

next build --profile

之后,您可以像在开发环境中一样使用性能分析器。

要了解有关 React 性能分析的更多信息,您可以阅读 React 团队关于 React Profiler 的文章。特别感谢 TODOrTotev@darshkpatel 为贡献此功能。

可选通配符路由

Next.js 9.2 添加了 对通配符动态路由的支持,这些路由已被社区广泛应用于各种用例。通配符路由使您能够创建由无头 CMS、GraphQL API、文件系统等驱动的、高度动态的路由结构。

在听取反馈意见后,我们了解到用户希望拥有更大的灵活性来匹配路由的最根级别。今天,我们很高兴地推出**可选通配符动态路由**以满足这些高级场景。

要创建可选通配符路由,您可以使用 `[[...slug]]` 语法创建页面。

例如,`pages/blog/[[...slug]].js` 将匹配 `/blog`,以及其下的任何路由,例如:`/blog/a`、`/blog/a/b/c` 等。

与通配符路由一样,`slug` 将作为路径部分的数组提供在 路由查询对象 中。因此,对于路径 `/blog/foo/bar`,查询对象将为 `{ slug: ['foo', 'bar'] }`。对于路径 `/blog`,查询对象将省略 slug 键:`{ }`。

您可以 在我们的文档中了解有关可选通配符路由的更多信息

Webpack 5 支持(测试版)

Webpack 5 目前处于测试阶段。它包含一些重大改进。

我们很高兴今天宣布 Next.js 的 Webpack 5 测试版可用。

要试用 Webpack 5,您可以在 `package.json` 中使用 Yarn 解析

package.json
{
  "resolutions": {
    "webpack": "^5.0.0-beta.30"
  }
}

Webpack 5 测试版已在 nextjs.orgvercel.com 的生产环境中推出。我们鼓励您以渐进的方式尝试它,并在 GitHub 上报告您的发现。

编译基础设施改进

为了支持 Webpack 5,我们重写了大量编译管道,使其更适合 Next.js。

  • Next.js 不再依赖于 `webpack-hot-middleware` 和 `webpack-dev-middleware`,而是直接使用 Webpack 并针对 Next.js 项目进行优化。这转化为更简单的架构和更快的开发编译。
  • 按需加载入口,这是 Next.js 用于在开发过程中编译您在特定时间访问的页面的系统,也已重写,并且现在通过利用专门针对我们的用例定制的新 Webpack 行为变得更加可靠。

  • React Fast Refresh 和 Next.js 错误覆盖层现在与 webpack 5 完全兼容。
  • 磁盘缓存将在未来的 Beta 版本中启用。

向后兼容性

我们始终致力于确保 Next.js 与以前的版本向后兼容。

Webpack 4 将继续得到完全支持。我们正在与 webpack 团队密切合作,以确保从 webpack 4 迁移到 webpack 5 尽可能顺利。

如果您的 Next.js 项目没有自定义 webpack 配置,则无需进行任何项目更改即可充分利用 webpack 5。

重要提示:如果您的项目具有自定义 webpack 配置,则可能需要进行一些更改才能过渡到 webpack 5。我们建议关注我们的迁移说明,或者完全最小化 webpack 扩展的使用,以便将来能够无缝升级。

macOS 上改进的文件监视

我们最近发现 webpack 中存在一个问题,即在 macOS 上对代码进行一些更改后,文件监视将停止。您需要手动重新启动项目才能再次查看更新。经过几次更改后,循环将重复。

此外,我们发现此问题不仅发生在 Next.js 项目中,还发生在所有构建在 webpack 之上的项目和框架中。

经过数天的调试,我们追溯到其根本原因是 webpack 使用的名为 chokidar 的文件监视实现,这是一个在 Node.js 生态系统中广泛使用的文件监视实现。

我们向chokidar 发送了一个补丁来修复此问题。发布补丁后,我们与Tobias Koppers合作,在一个新的 webpack 版本中推出了此补丁。

当您升级到 Next.js 9.5 时,将自动使用此已修补的 webpack 版本。

结论

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

  • 我们拥有超过1,200名独立贡献者**,**自 9.4 版本发布以来,新增贡献者超过135名。
  • 在 GitHub 上,该项目获得了超过51,100次星标。

GitHub Discussions上加入 Next.js 社区。Discussions 是一个社区空间,可让您与其他 Next.js 用户联系,并自由提问或分享您的作品。

例如,您可能希望首先与大家分享您的项目 URL

如果您想回馈但不知道如何操作,我们鼓励您尝试实验性功能(例如我们的 Webpack 支持)并报告您的发现!

鸣谢

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

特别感谢Jan Potoms,一位长期活跃的 Next.js 社区成员,他为本次发布的多个功能做出了贡献。

特别感谢Tobias Koppers,webpack 的作者,他帮助在 Next.js 中实现了 webpack 5 支持。

此版本由以下人员的贡献带来:@chandan-reddy-k、@Timer、@aralroca、@artemisart、@sospedra、@prateekbh、@Prioe、@Janpot、@merceyz、@ijjk、@PavelK27、@marbiano、@MichelleLucero、@thorsten-stripe、@TODOrTotev、@Skn0tt、@lfades、@timneutkens、@akhila-ariyachandra、@chibicode、@rafaelalmeidatk、@kirill-konshin、@jamesvidler、@JeffersonBledsoe、@tylev、@jamesmosier、@filipemarins、@Remeic、@vvo、@timothyis、@jazibsawar、@coetry、@adam-zacharski、@danwilliams、@tywmick、@matamatanot、@goldins、@mvllow、@its-tayo、@sshyam-gupta、@wilbert-abreu、@sebastianbenz、@jaydenseric、@developit、@dylanjha、@darshkpatel、@spinks、@stefanprobst、@moh12594、@jasonmerino、@cristiand391、@HyunSangHan、@mcsdevv、@M1ck0、@hydRAnger、@alexej-d、@valmassoi、@motleydev、@eKhattak、@jpedroschmitz、@JerryGoyal、@bowen31337、@phillip055、@balazsorban44、@chuabingquan、@youhosi、@andresz1、@bell-steven、@areai51、@Wssn、@ndom91、@anthonyshort、@zxzl、@jbowes、@IamLizu、@PascalPixel、@ralphilius、@ysun62、@muslax、@elsigh、@AsherFoster、@botv、@tomdohnal、@christianalfoni、@tomasztunik、@gsimone、@illuminist、@jplew、@OskarKaminski、@RickyAbell、@steph-query、@ericgoe、@MalvinJay、@cristianbote、@Ashikpaul、@jensmeindertsma、@amorriscode、@abhik-b、@awareness481、@LukasPolak、@arvigeus、@romMidnight、@jackyef、@drumm2k、@kuldeepkeshwar、@bogy0、@Belco90、@wawjr3d、@tanmaylaud、@SarKurd、@kevinsproles、@dstotijn、@styfle、@blackwright、@BrunoBernardino、@heyAyushh、@Necmttn、@TrySound、@obedparla、@NyashaNziramasanga、@tonyspiro、@kukicado、@ceorourke、@MehediH、@robintom、@karlhorky 和 @tcK1!