|
| 1 | +--- |
| 2 | +source-updated-at: 2025-05-29T18:05:49.000Z |
| 3 | +translation-updated-at: 2025-05-29T19:21:52.289Z |
| 4 | +title: Next.js 9.2 版本发布 |
| 5 | +description: >- |
| 6 | + Next.js 9.2 引入了对 CSS 的原生支持、激进的代码分割策略、全捕获动态路由等新特性! |
| 7 | +author: |
| 8 | + - name: JJ Kasper |
| 9 | + image: /static/team/jj.jpg |
| 10 | + - name: Joe Haddad |
| 11 | + image: /static/team/timer.jpg |
| 12 | + - name: Luis Alvarez |
| 13 | + image: /static/team/lfades.jpg |
| 14 | + - name: Tim Neutkens |
| 15 | + image: /static/team/tim.jpg |
| 16 | +date: 2020-01-15T19:37:43.618Z |
| 17 | +image: >- |
| 18 | + https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/next-9-2/twitter-card.png |
| 19 | +--- |
| 20 | + |
| 21 | +今天我们很高兴地推出 Next.js 9.2,主要特性包括: |
| 22 | + |
| 23 | +* **[全局样式表的原生 CSS 支持](#built-in-css-support-for-global-stylesheets)**:应用现在可以直接导入 `.css` 文件作为全局样式表。 |
| 24 | +* **[组件级样式的原生 CSS 模块支持](#built-in-css-module-support-for-component-level-styles)**:通过 `.module.css` 命名约定,可以在应用的任何位置导入和使用局部作用域的 CSS。 |
| 25 | +* **[改进的代码分割策略](#improved-code-splitting-strategy)**:Google Chrome 团队深度优化了 Next.js 的代码分割策略,显著减小了客户端包体积。同时最大化利用了 [HTTP/2](https://developers.google.com/web/fundamentals/performance/http2) 来提升页面加载速度,且不影响 HTTP/1.1 性能。 |
| 26 | +* **[全捕获动态路由](#catch-all-dynamic-routes)**:Next.js 动态路由现在支持全捕获路由,可满足更多使用场景,例如基于 CMS 的网站。 |
| 27 | + |
| 28 | +所有这些改进都是非破坏性的,完全向后兼容。只需运行以下命令即可更新: |
| 29 | + |
| 30 | +```bash filename="终端" |
| 31 | +npm i next@latest react@latest react-dom@latest |
| 32 | +``` |
| 33 | + |
| 34 | +### [全局样式表的原生 CSS 支持](#built-in-css-support-for-global-stylesheets) |
| 35 | + |
| 36 | +Next.js 5 通过名为 `next-css` 的自定义插件引入了 CSS 导入支持,该插件扩展了 Next.js 的行为。 |
| 37 | + |
| 38 | +长期以来,我们收到来自企业和 Next.js 用户的一致反馈,表示他们经常需要在应用中添加 `next-css`。 |
| 39 | + |
| 40 | +此外,`next-css` 在导入 CSS 时存在一些约束缺失的问题。例如,可以在项目的每个文件中导入 CSS 文件,但这些 CSS 文件会对整个应用产生全局影响。 |
| 41 | + |
| 42 | +为了提升开发者体验并解决这些问题,我们开始着手为 Next.js 默认添加 CSS 导入支持。 |
| 43 | + |
| 44 | +我们很高兴地宣布,Next.js 现在原生支持将样式表导入到应用中。 |
| 45 | + |
| 46 | +要在应用中使用 CSS 导入,请在 `pages/_app.js` 中导入 CSS 文件。 |
| 47 | + |
| 48 | +例如,假设项目根目录下有一个名为 `styles.css` 的样式表: |
| 49 | + |
| 50 | +``` |
| 51 | +body { |
| 52 | + padding: 20px 20px 60px; |
| 53 | + margin: 0; |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +如果尚未创建 [`pages/_app.js` 文件](/docs/pages/building-your-application/routing/custom-app),请先创建。 |
| 58 | + |
| 59 | +然后导入 `styles.css` 文件: |
| 60 | + |
| 61 | +```js filename="pages/_app.js" |
| 62 | +import '../styles.css'; |
| 63 | + |
| 64 | +// 在新建的 `pages/_app.js` 文件中必须包含此默认导出。 |
| 65 | +export default function MyApp({ Component, pageProps }) { |
| 66 | + return <Component {...pageProps} />; |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +由于样式表本质上是全局的,因此必须在[自定义 `<App>` 组件](/docs/pages/building-your-application/routing/custom-app)中导入。这对于避免全局样式的类名冲突和顺序问题非常必要。 |
| 71 | + |
| 72 | +在开发环境中,这种样式表表达方式允许你在编辑样式时自动更新页面上的样式。 |
| 73 | + |
| 74 | +在生产环境中,所有 CSS 文件会自动合并为一个经过压缩的 `.css` 文件。该 CSS 文件将通过 `<link>` 标签加载,并自动注入到 Next.js 生成的默认 HTML 标记中。 |
| 75 | + |
| 76 | +这一新特性完全向后兼容。如果正在使用 `@zeit/next-css` 或其他 CSS 相关插件,该特性会被禁用以避免冲突。 |
| 77 | + |
| 78 | +如果当前正在使用 `@zeit/next-css`,建议从 `next.config.js` 和 `package.json` 中移除该插件,升级后即可使用内置的 CSS 支持。 |
| 79 | + |
| 80 | +### [组件级样式的原生 CSS 模块支持](#built-in-css-module-support-for-component-level-styles) |
| 81 | + |
| 82 | +Next.js 现在支持使用 `[name].module.css` 文件命名约定的 [CSS 模块](https://github.com/css-modules/css-modules)。 |
| 83 | + |
| 84 | +与 Next.js 5 中通过 `next-css` 提供的支持不同,[全局 CSS](#built-in-css-support-for-global-stylesheets) 和 CSS 模块现在可以**共存**——`next-css` 要求应用中的所有 `.css` 文件要么作为全局样式处理,要么作为局部样式处理,但不能同时处理。 |
| 85 | + |
| 86 | +CSS 模块通过自动创建唯一的类名来实现 CSS 的局部作用域。这允许你在不同文件中使用相同的 CSS 类名,而无需担心冲突。 |
| 87 | + |
| 88 | +这种行为使 CSS 模块成为包含组件级 CSS 的理想方式。CSS 模块文件**可以在应用的任何位置导入**。 |
| 89 | + |
| 90 | +例如,假设 `components/` 文件夹中有一个可复用的 `Button` 组件: |
| 91 | + |
| 92 | +首先,创建 `components/Button.module.css`,内容如下: |
| 93 | + |
| 94 | +``` |
| 95 | +/* |
| 96 | +无需担心 .error {} 与其他 `.css` 或 `.module.css` 文件冲突! |
| 97 | +*/ |
| 98 | +.error { |
| 99 | + color: white; |
| 100 | + background-color: red; |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +然后,创建 `components/Button.js`,导入并使用上述 CSS 文件: |
| 105 | + |
| 106 | +```js filename="components/Button.js" |
| 107 | +import styles from './Button.module.css'; |
| 108 | + |
| 109 | +export function Button() { |
| 110 | + return ( |
| 111 | + <button |
| 112 | + type="button" |
| 113 | + // 注意 "error" 类是作为导入的 `styles` 对象的一个属性访问的。 |
| 114 | + className={styles.error} |
| 115 | + > |
| 116 | + 销毁 |
| 117 | + </button> |
| 118 | + ); |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | +CSS 模块是一个_可选_特性,仅对扩展名为 `.module.css` 的文件启用。常规的 [`<link>` 样式表](/docs/pages/api-reference/components/head)和[全局 CSS 文件](#built-in-css-support-for-global-stylesheets)仍然受支持。 |
| 123 | + |
| 124 | +在生产环境中,所有 CSS 模块文件会自动合并为**多个经过压缩和代码分割的 `.css` 文件**。这些 `.css` 文件代表了应用中的热执行路径,确保为每个页面加载最少数量的 CSS 以实现绘制。 |
| 125 | + |
| 126 | +与上述类似,这一新特性完全向后兼容。如果正在使用 `@zeit/next-css` 或其他 CSS 相关插件,该特性会被禁用以避免冲突。 |
| 127 | + |
| 128 | +如果当前正在使用 `@zeit/next-css`,建议从 `next.config.js` 和 `package.json` 中移除该插件,升级后即可使用内置的 CSS 支持。 |
| 129 | + |
| 130 | +### [改进的代码分割策略](#improved-code-splitting-strategy) |
| 131 | + |
| 132 | +Next.js 9.2 之前的版本有一组固定的 JavaScript 包需要加载才能使页面交互: |
| 133 | + |
| 134 | +* 页面的 JavaScript 文件 |
| 135 | +* 包含公共 JavaScript 的文件 |
| 136 | +* Next.js 客户端运行时包 |
| 137 | +* Webpack 客户端运行时包 |
| 138 | +* 动态导入(通过 `next/dynamic` 添加,使用时) |
| 139 | + |
| 140 | +为了使页面交互,所有这些包都必须加载,因为它们相互依赖以在浏览器中启动 React。 |
| 141 | + |
| 142 | +由于所有这些包都是应用变得交互所必需的,因此尽可能优化它们非常重要。实际上,这意味着不过度下载应用中其他部分的代码。 |
| 143 | + |
| 144 | +因此,Next.js 使用了一个 `commons` 包来存放页面之间的公共 JavaScript。旧的分包策略生成 `commons` 的计算基于使用率启发式。如果一个模块在超过 50% 的页面中使用,它会被标记为公共模块。否则,它会被打包到页面的 JavaScript 文件中。 |
| 145 | + |
| 146 | +然而,应用可能包含许多不同类型的页面。例如,营销页面、博客和仪表盘。如果营销页面的数量远多于其他类型的页面,公共模块的计算结果会主要针对营销页面进行优化。 |
| 147 | + |
| 148 | +我们的目标是在一个应用中优化所有类型的页面。 |
| 149 | + |
| 150 | +[Alex Castle](https://twitter.com/atcastle) [提出了一种新的分包方法](https://github.com/vercel/next.js/issues/7631),允许多个文件进行优化的公共分包,包括涉及多种页面类型的情况。 |
| 151 | + |
| 152 | +今天,我们很高兴地宣布这一新的分包行为在 Next.js 9.2 中默认启用。我们要向 [Google Chrome 团队](/blog/next-9#google-chrome-collaboration) 和 [Alex Castle](https://twitter.com/atcastle) 致以深深的谢意,感谢他们贡献这一变更。这一变更反映了数周的研究、实验室测试、真实世界测试和实施的累积成果。 |
| 153 | + |
| 154 | +新的分包实现利用 [HTTP/2](https://developers.google.com/web/fundamentals/performance/http2) 来交付更多数量的小体积分包。 |
| 155 | + |
| 156 | +根据新的启发式方法,分包创建包括: |
| 157 | + |
| 158 | +* 每个页面的最小分包。 |
| 159 | +* 包含 React、ReactDOM、React 调度程序等的框架分包。 |
| 160 | +* 任何超过 160KB(预压缩/预最小化)的 `node_module` 依赖项的库分包。 |
| 161 | +* 用于所有页面共享代码的公共分包。 |
| 162 | +* 尽可能多的共享分包(由 2 个或更多页面使用),优化整体应用大小和初始加载速度。 |
| 163 | +* Next.js 的客户端运行时。 |
| 164 | +* Webpack 运行时。 |
| 165 | + |
| 166 | +让我们看看这在真实应用中的表现: |
| 167 | + |
| 168 | +早期采用的行业合作伙伴 [Barnebys®](https://www.barnebys.com/) 的整体应用大小减少了 23%。 |
| 169 | + |
| 170 | +此外,他们最大的 JS 包减少了 30%——从 605kB 降至 425kB——且无需任何代码更改。 |
| 171 | + |
| 172 | +另一家行业合作伙伴 [SumUp®](https://sumup.com/) 的最大 JS 包减少了 70%——从 395kB 降至 122kB——同样无需任何代码更改。 |
| 173 | + |
| 174 | +#### [最大 JavaScript 包](#largest-javascript-bundle) |
| 175 | + |
| 176 | +之前 |
| 177 | + |
| 178 | +之后 |
| 179 | + |
| 180 | +变化 |
| 181 | + |
| 182 | +Barnebys |
| 183 | + |
| 184 | +605kB |
| 185 | + |
| 186 | +425kB |
| 187 | + |
| 188 | +**减少 30%** |
| 189 | + |
| 190 | +SumUp |
| 191 | + |
| 192 | +395kB |
| 193 | + |
| 194 | +122kB |
| 195 | + |
| 196 | +**减少 70%** |
| 197 | + |
| 198 | +新的分包行为不仅减少了整体和初始加载大小,还优化了后续的客户端导航。[Barnebys®](https://www.barnebys.com/) 在六 (6) 次页面导航后加载的 JavaScript 量减少了 87%: |
| 199 | + |
| 200 | +#### [多次客户端跳转加载的 JavaScript](#javascript-loaded-by-multiple-client-side-transitions) |
| 201 | + |
| 202 | +之前 |
| 203 | + |
| 204 | +之后 |
| 205 | + |
| 206 | +变化 |
| 207 | + |
| 208 | +Barnebys |
| 209 | + |
| 210 | +136kB |
| 211 | + |
| 212 | +18kB |
| 213 | + |
| 214 | +**减少 87%** |
| 215 | + |
| 216 | +这一新行为完全向后兼容。只需升级到最新版本的 Next.js 即可利用这一性能改进。 |
| 217 | + |
| 218 | +### [全捕获动态路由](#catch-all-dynamic-routes) |
| 219 | + |
| 220 | +随着 Next.js 9 的发布,我们引入了[动态路由段](https://nextjs.org/blog/next-9#dynamic-route-segments),旨在简化 Next.js 中的动态段,无需自定义服务器。这一特性已被 Next.js 用户广泛采用。 |
| 221 | + |
| 222 | +但仍有一些情况是动态路由段特性未涵盖的。 |
| 223 | + |
| 224 | +其中之一是全捕获路由。例如,将通配符如 `/post/**` 路由为一个页面。这对于具有嵌套结构(例如由 CMS 等内容源定义的结构)特别有用。 |
| 225 | + |
| 226 | +现在可以使用 `[...name]` 语法创建全捕获动态路由。 |
| 227 | + |
| 228 | +例如,`pages/post/[...slug].js` 将匹配 `/post/a`、`/post/a/b`、`/post/a/b/c` 等路径。 |
| 229 | + |
| 230 | +`slug` 将在路由查询对象中作为路径部分的数组提供。因此,对于路径 `/post/foo/bar`,查询对象将是 `{ slug: ['foo', 'bar'] }`。 |
| 231 | + |
| 232 | +[社区](#community) |
| 233 | +----------------------- |
| 234 | + |
| 235 | +我们非常高兴看到 Next.js 的采用持续增长: |
| 236 | + |
| 237 | +* 我们有超过 **880** 名独立贡献者。 |
| 238 | +* 在 GitHub 上,该项目已获得超过 **44,000** 次星标。 |
| 239 | +* [示例目录](https://github.com/vercel/next.js/tree/canary/examples) 包含超过 **220** 个示例。 |
| 240 | + |
| 241 | +Next.js 社区现在有超过 **13,800** 名成员。[加入我们!](https://github.com/vercel/next.js/discussions) |
| 242 | + |
| 243 | +我们感谢我们的社区以及所有帮助塑造此版本的外部反馈和贡献。 |
0 commit comments