跳到内容
返回博客

2020年1月15日,星期三

Next.js 9.2

发布者

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

  • 内置 CSS 支持全局样式表:应用程序现在可以直接导入 .css 文件作为全局样式表。
  • 内置 CSS 模块支持组件级样式:利用 .module.css 约定,局部作用域的 CSS 可以被导入并在应用程序的任何地方使用。
  • 改进的代码分割策略:Google Chrome 团队极大地优化了 Next.js 的代码分割策略,显著减小了客户端捆绑包的大小。此外,他们最大限度地利用了 HTTP/2,以提高页面加载速度,同时不影响 HTTP/1.1 性能。
  • 全捕获动态路由:Next.js 的动态路由现在支持全捕获路由,支持各种新的用例,例如由 CMS 支持的网站。

所有这些优势都是非破坏性的,并且完全向后兼容。您所需要做的就是运行

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

内置 CSS 支持全局样式表

Next.js 5 通过一个名为 next-css 的自定义插件引入了对导入 CSS 的支持,该插件扩展了 Next.js 的行为。

随着时间的推移,我们收到了 Next.js 公司和用户的一致反馈,他们提到经常会向应用程序添加 next-css

此外,next-css 在导入 CSS 时存在一些缺失的限制。例如,您可以在项目的每个文件中导入一个 CSS 文件,但是这个导入的 CSS 文件将是整个应用程序的全局文件。

为了改善开发者体验并解决这些不一致性,我们开始默认将 CSS 导入支持引入 Next.js。

我们很高兴地宣布 Next.js 现在原生支持将样式表导入您的应用程序。

要开始在应用程序中使用 CSS 导入,请在 pages/_app.js 中导入 CSS 文件。

例如,考虑您项目根目录下的名为 styles.css 的样式表

body {
  padding: 20px 20px 60px;
  margin: 0;
}

如果尚不存在,请创建一个pages/_app.js 文件

然后,导入 styles.css 文件

pages/_app.js
import '../styles.css';
 
// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />;
}

由于样式表本质上是全局的,它们必须在 自定义 <App> 组件中导入。这是为了避免全局样式的类名和顺序冲突所必需的。

在开发环境中,以这种方式表达样式允许您的样式在您编辑它们时自动在页面上更新。

在生产环境中,所有 CSS 文件将自动合并为一个最小化的 .css 文件。此 CSS 文件将通过 <link> 标签加载,并自动注入到 Next.js 生成的默认 HTML 标记中。

这个新功能完全向后兼容。如果您正在使用 @zeit/next-css 或其他与 CSS 相关的插件,该功能将被禁用以避免冲突。

如果您目前正在使用 @zeit/next-css,我们建议您从 next.config.jspackage.json 中删除该插件,从而在升级后转向内置的 CSS 支持。

内置 CSS 模块支持组件级样式

Next.js 现在支持 CSS 模块,使用 [name].module.css 文件命名约定。

与 Next.js 5 之前使用 next-css 提供的支持不同,全局 CSS 和 CSS 模块现在可以共存——next-css 要求应用程序中的所有 .css 文件都作为全局或局部处理,但不能两者兼有。

CSS 模块通过自动创建唯一的类名来局部化 CSS。这允许您在不同的文件中使用相同的 CSS 类名,而不必担心冲突。

此行为使 CSS 模块成为包含组件级 CSS 的理想方式。CSS 模块文件可以在您应用程序的任何地方导入

例如,考虑 components/ 文件夹中可重用的 Button 组件

首先,创建 components/Button.module.css,内容如下

/*
You do not need to worry about .error {} colliding with any other `.css` or
`.module.css` files!
*/
.error {
  color: white;
  background-color: red;
}

然后,创建 components/Button.js,导入并使用上述 CSS 文件

components/Button.js
import styles from './Button.module.css';
 
export function Button() {
  return (
    <button
      type="button"
      // Note how the "error" class is accessed as a property on the imported
      // `styles` object.
      className={styles.error}
    >
      Destroy
    </button>
  );
}

CSS 模块是可选功能,仅对扩展名为 .module.css 的文件启用。常规的 <link> 样式表全局 CSS 文件仍然受支持。

在生产环境中,所有 CSS 模块文件会自动合并为许多经过最小化和代码分割的 .css 文件。这些 .css 文件代表您应用程序中的热门执行路径,确保为您的应用程序每页加载最少量的 CSS。

如上所述,这个新功能完全向后兼容。如果您正在使用 @zeit/next-css 或其他与 CSS 相关的插件,该功能将被禁用以避免冲突。

如果您目前正在使用 @zeit/next-css,我们建议您从 next.config.jspackage.json 中删除该插件,从而转而使用内置的 CSS 支持。

改进的代码分割策略

Next.js 9.2 之前的版本有一组固定的 JavaScript 捆绑包,这些捆绑包是加载和使页面可交互所需的。

  • 页面的 JavaScript 文件
  • 一个包含通用 JavaScript 的文件
  • Next.js 客户端运行时捆绑包
  • Webpack 客户端运行时捆绑包
  • 动态导入(在使用 next/dynamic 时添加)

要使页面具有交互性,所有这些捆绑包都必须加载,因为它们相互依赖才能在浏览器中启动 React。

由于所有这些捆绑包都是应用程序变得可交互所必需的,因此尽可能地优化它们非常重要。实际上,这意味着不要从应用程序的其他部分过度下载代码。

因此,Next.js 使用了一个 commons 捆绑包,其中包含页面之间共享的 JavaScript。旧的捆绑包分割策略计算生成 commons 采用的是使用率启发式算法。如果一个模块在所有页面中使用了超过 50%,它就会被标记为通用模块。否则,它会被捆绑到页面的 JavaScript 文件中。

然而,应用程序可能由许多不同类型的页面组成。例如,营销页面、博客和仪表板。如果营销页面数量远多于其他页面类型,则通用计算将导致优化严重偏向营销页面。

我们的目标是在一个应用程序中优化所有页面类型。

Alex Castle 提出了一种新的分块方法(创建单独的 JavaScript 文件),该方法允许使用多个文件进行优化的公共块,包括涉及多种页面类型的情况。

今天,我们很高兴地宣布 Next.js 9.2 默认启用这种新的分块行为。我们衷心感谢 Google Chrome 团队Alex Castle 对此更改的贡献。此更改反映了数周的研究、实验室测试、实际测试和实施的累积努力。

新的分块实现利用 HTTP/2 来交付更多更小的块。

在新启发式算法下,会创建以下块:

  • 每个页面的最小块。
  • 包含 React、ReactDOM、React 的调度器等的前端框架块。
  • 所有超过 160kb(预最小化/gzip)的 node_module 依赖项的库块
  • 所有页面共用的公共代码块。
  • 尽可能多的共享块(被 2 个或更多页面使用),以优化整体应用程序大小和初始加载速度。
  • Next.js 的客户端运行时。
  • Webpack 运行时。

让我们看看这在实际应用中意味着什么

早期采纳的行业伙伴 Barnebys® 发现其整体应用程序大小减少了 23%。

此外,他们最大的 JS 捆绑包减少了 30%——从 605kB 减少到 425kB——且无需更改任何代码。

另一个行业合作伙伴 SumUp® 发现其最大的 JS 捆绑包减少了 70%——从 395kB 减少到 122kB——且无需更改任何代码。

最大的 JavaScript 捆绑包

之前之后差额
巴内比斯(Barnebys)605kB425kB小 30%
SumUp395kB122kB小 70%

新的分块行为不仅减少了您的整体和初始加载大小,还减少了后续的客户端导航。Barnebys® 在六 (6) 次页面导航后,加载的 JavaScript 量减少了 87%。

多次客户端转换加载的 JavaScript

之前之后差额
巴内比斯(Barnebys)136kB18kB小 87%

这个新行为完全向后兼容。您只需升级到最新版本的 Next.js 即可利用此性能改进。

全捕获动态路由

随着 Next.js 9 的发布,我们引入了 动态路由段,旨在简化 Next.js 中的动态段,而无需自定义服务器。此功能已被 Next.js 用户广泛采用。

仍然有一些动态路由段功能未涵盖的情况。

其中一个案例是全捕获路由。例如,将 /post/** 这样的通配符路由到一个页面。当您有一个由 CMS 等内容源定义的嵌套结构时,这特别有用。

您现在可以使用 [...name] 语法创建全捕获动态路由。

例如,pages/post/[...slug].js 将匹配 /post/a/post/a/b/post/a/b/c 等等。

slug 将作为单个路径部分的数组在路由器查询对象中提供。因此,对于路径 /post/foo/bar,查询对象将是 { slug: ['foo', 'bar'] }

社区

我们非常高兴地看到 Next.js 的采用率持续增长

  • 我们已经拥有超过 880 名独立贡献者。
  • 在 GitHub 上,该项目已被标星超过 44,000 次。
  • 示例目录 包含超过 220 个示例。

Next.js 社区目前拥有超过 13,800 名成员。加入我们!

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