跳到内容
返回博客

2020 年 1 月 15 日,星期三

Next.js 9.2

发布者:

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

  • 内置 CSS 全局样式表支持:应用程序现在可以直接导入 .css 文件作为全局样式表。
  • 内置 CSS 模块组件级样式支持:利用 .module.css 约定,可以导入本地作用域的 CSS,并在应用程序中的任何位置使用。
  • 改进的代码拆分策略:Google Chrome 团队大力优化了 Next.js 的代码拆分策略,从而显著缩小了客户端 bundle 的体积。此外,他们最大限度地利用了 HTTP/2 以提高页面加载速度,同时不影响 HTTP/1.1 的性能。
  • Catch-All 动态路由:Next.js 的动态路由现在支持 catch-all 路由,支持各种新的用例,例如,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 文件尚不存在,请创建一个 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 现在支持使用 [name].module.css 文件命名约定的 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 支持。

改进的代码拆分策略

9.2 之前的 Next.js 版本具有一组固定的 JavaScript bundle,这些 bundle 是加载页面并使其可交互所必需的:

  • 页面的 JavaScript 文件
  • 包含通用 JavaScript 的文件
  • Next.js 客户端运行时 bundle
  • Webpack 客户端运行时 bundle
  • 动态导入(通过 next/dynamic 添加,如果使用)

为了使页面可交互,所有这些 bundle 都必须加载,因为它们相互依赖才能在浏览器中启动 React。

由于应用程序变为可交互状态需要所有这些 bundle,因此尽可能优化它们非常重要。实际上,这意味着不要过度下载应用程序其他部分的代码。

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

但是,应用程序可以由许多不同类型的页面组成。例如,营销页面、博客和仪表板。如果营销页面的数量远多于其他页面类型,则 commons 计算将导致优化主要集中在营销页面上。

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

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

今天,我们很高兴地宣布,这种新的分块行为在 Next.js 9.2 中默认启用。我们要向 Google Chrome 团队Alex Castle 表示衷心的感谢,感谢他们为此更改做出的贡献。此更改反映了数周的研究、实验室测试、真实世界测试和实施的累积成果。

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

在新启发式方法下,为以下内容创建 chunk:

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

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

早期采用的行业合作伙伴 Barnebys® 看到整体应用程序大小减少了 23%。

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

另一家行业合作伙伴 SumUp® 看到他们最大的 JS bundle 减少了 70% — 从 395kB 减少到 122kB — 无需任何代码更改。

最大 JavaScript Bundle

之前之后变化
Barnebys605kB425kB30% 更小
SumUp395kB122kB70% 更小

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

多次客户端过渡加载的 JavaScript

之前之后变化
Barnebys136kB18kB87% 更小

这种新行为是完全向后兼容的。升级到最新版本的 Next.js 是您充分利用此性能改进所需做的全部操作。

Catch-All 动态路由

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

动态路由段功能仍然有一些案例没有涵盖。

其中一个案例是 catch-all 路由。例如,将像 /post/** 这样的通配符路由作为页面。当您拥有由内容源(如 CMS)定义的嵌套结构时,这尤其有用。

您现在可以使用 [...name] 语法创建 catch-all 动态路由。

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

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

社区

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

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

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

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