2023 年 2 月 23 日,星期四
Next.js 13.2
发布者Next.js 13.2 包括对 App Router (app
) 的重大改进,为稳定性做准备
- 内置 SEO 支持: 新的 Metadata API 用于设置静态和动态
meta
标签。 - 路由处理器: 自定义请求处理器,构建于 Web
Request
和Response
之上。 - 用于服务器组件的 MDX: 在 Markdown 中使用 React 组件,仅限服务器端。
- Rust MDX 解析器: 使用全新的 Rust 插件实现更快的 Markdown 解析。
- 改进的错误覆盖层: 分离 Next.js 和 React 堆栈跟踪,以提高可读性。
- 静态类型链接 (Beta): 使用
next/link
和 TypeScript 预防链接断开。 - Turbopack 改进 (Alpha): 兼容 Webpack 加载器并改进支持。
- Next.js 缓存 (Beta): 渐进式 ISR 和更快的代码更改重新部署。
立即运行以下命令更新
npm i next@latest react@latest react-dom@latest eslint-config-next@latest
内置 SEO 支持,带有新的 Metadata API
Next.js 从一开始就被设计为启用搜索引擎优化。
提供预渲染的 HTML 内容不仅有助于改进搜索引擎的索引,还有助于提高应用程序的性能。虽然 Next.js 已经为修改应用程序中的元数据 (next/head
) 提供了简单的 API 很多版本,但我们希望重新设计和增强您如何使用 App Router (app
) 优化搜索引擎。
新的 Metadata API 允许您在作为服务器组件的任何布局或页面中,使用显式的元数据配置来定义元数据(例如 HTML head
元素内的 meta
和 link
标签)。
import type { Metadata } from 'next';
export const metadata: Metadata = {
title: 'Home',
description: 'Welcome to Next.js',
};
此 API 简单、可组合,并且设计为与流式服务器渲染兼容。例如,您可以在根布局中为整个应用程序设置通用的元数据属性,并在应用程序中的其他路由中组合和合并元数据对象。
这包括对动态元数据以及静态元数据的支持
// Static metadata
export const metadata = {
title: '...',
};
// Dynamic metadata
export async function generateMetadata({ params, searchParams }) {
const product = await getProduct(params.id);
return { title: product.title };
}
所有元数据选项都可用,包括提供自定义元数据的功能,并通过 TypeScript 插件 或添加 Metadata
类型来支持 TypeScript。
例如,您可以通过元数据定义 open graph 图像
export const metadata = {
openGraph: {
title: 'Next.js',
description: 'The React Framework for the Web',
url: 'https://nextjs.net.cn',
siteName: 'Next.js',
images: [
{
url: 'https://nextjs.net.cn/og.png',
width: 800,
height: 600,
},
],
locale: 'en-US',
type: 'website',
},
};
export default function Layout({ children }) {}
Metadata API 在 13.2 版本中可用于 App Router (app
),取代了之前的 head.js
特殊文件。它不适用于 pages
目录。
了解更多关于 SEO 的信息 或查看 Metadata 的 API 参考。我们要感谢 next-seo 对社区包的工作以及对初始 API 设计的反馈。
自定义路由处理器
App Router (app
) 原始 beta 版本的缺失部分之一是 API 路由,它存在于 pages/api
目录中。我们想借此机会创建一个新的、更现代的 API 路由版本,该版本与 app
的新路由系统深度集成。
路由处理器允许您使用 Web Request 和 Response API 为给定路由创建自定义请求处理器。
export async function GET(request: Request) {}
路由处理器具有同构 API,可以无缝支持 Edge 和 Node.js 运行时,包括对流式响应的支持。由于路由处理器使用与页面和布局相同的 路由段配置,因此它们支持期待已久的功能,例如通用 静态渲染 和 重新验证。
route.ts
文件可以导出由 HTTP 动词命名的异步函数:GET
、HEAD
、OPTIONS
、POST
、PUT
、DELETE
和 PATCH
。然后可以包装和抽象这些函数,为您的自定义路由逻辑创建助手/可重用逻辑。
其他服务器函数(如 cookies
和 headers
)可以在路由处理器内部使用,以及构建这些抽象的任何 Web API。这允许在服务器组件和路由处理器之间共享代码。
import { cookies } from 'next/headers';
export async function GET(request: Request) {
const cookieStore = cookies();
const token = cookieStore.get('token');
return new Response('Hello, Next.js!', {
status: 200,
headers: { 'Set-Cookie': `token=${token}` },
});
}
路由处理器在 13.2 版本中可用于 App Router (app
),使用 route.ts
特殊文件。它们在 pages
目录中不可用,因为它们是 API 路由的替代品。
了解更多关于路由处理器的信息 或 查看 API 参考。我们要感谢 SvelteKit 在此处的 先前的技术和灵感。
用于服务器组件的 MDX
MDX 是 markdown 的超集,允许您直接在 markdown 文件中编写 JSX。这是一种在内容中添加动态交互性并嵌入 React 组件的强大方法。
在 13.2 版本中,您现在可以完全将 MDX 与 React 服务器组件一起使用 – 这意味着更少的客户端 JavaScript 以实现更快的页面加载,同时保留 React 用于模板化动态 UI 的强大功能。您可以根据需要在 MDX 内容中添加交互性。
@next/mdx
插件已更新,支持新的特殊文件 mdx-components.js|ts
,该文件在应用程序的根目录中定义,以提供自定义组件
// This file allows you to provide custom React components
// to be used in MDX files. You can import and use any
// React component you want, including components from
// other libraries.
function H1({ children }) {
// ...
}
function H2({ children }) {
// ...
}
export function useMDXComponents(components) {
return { h1: H1, h2: H2, ...components };
}
此外,我们还与社区包合作,以获取 MDX 内容 next-mdx-remote
和 contentlayer
,以添加对 React 服务器组件的支持。
了解更多关于如何使用服务器组件设置 MDX 的信息 或 部署我们的示例。
Rust MDX 解析器
作为启用 MDX for Server Components 的一部分,我们还用 Rust 重写了 MDX 解析器以提高性能。与之前的基于 JavaScript 的解析器相比,这是一个重大改进,后者在处理大量 MDX 文件时会出现明显的减速。
您可以选择在 next.config.js
中使用 Rust 解析器。例如,使用 @next/mdx
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
mdxRs: true,
},
};
const withMDX = require('@next/mdx')();
module.exports = withMDX(nextConfig);
我们要感谢 Titus Wormer,我们赞助他从事这个项目。如果您想在 Next.js 之外使用它,请查看新的软件包 mdxjs-rs。
静态类型链接
Next.js 现在可以在 app
目录中静态地键入链接,以防止在使用 next/link
时出现拼写错误和其他错误,从而提高在页面之间导航时的类型安全性。
import Link from 'next/link'
// ✅
<Link href="/about" />
// ✅
<Link href="/blog/nextjs" />
// ✅
<Link href={`/blog/${slug}`} />
// ❌ TypeScript errors if href is not a valid route
<Link href="/aboot" />
此功能需要使用新的 App Router 以及 TypeScript。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
typedRoutes: true,
},
};
module.exports = nextConfig;
此功能现已在 Beta 版中提供。 rewrites
和 redirects
尚不支持。
改进的错误覆盖层
为了帮助提高错误的可读性和可调试性,我们对 Next.js 错误覆盖层进行了一些改进。
在 13.2 版本中,Next.js 和 React 堆栈跟踪现在已分离,从而更容易识别错误的来源。此外,错误覆盖层现在显示 Next.js 的当前版本,帮助您了解您的版本是否为最新版本。

我们还改进了 React 水合错误的错误输出,现在这些错误输出更具可读性且更易于调试。
Turbopack 改进
Turbopack,在 Next.js 13 中以 alpha 版本发布,是一个增量打包器,旨在加速本地开发以及未来的生产构建。
我们一直专注于在 Turbopack 中支持现有的 Next.js 功能,并在我们向 Beta 版迈进的过程中提高整体稳定性。自上次发布以来,我们添加了
- 对
next/dynamic
的支持 - 在
next.config.js
中对rewrites
、redirects
、headers
和pageExtensions
的支持 - 对
pages
中的 404 错误和错误页面的支持 - 对 CSS 模块
composes: ... from ...
的支持 - 改进了 Fast Refresh 的可靠性和错误恢复
- 改进了 CSS 优先级处理
- 改进了编译时评估
我们还修复了许多错误并提高了稳定性,同时通过我们一些最大的内部 Next.js 应用程序和早期的 Vercel 客户对 Turbopack 进行了内部测试。
使用 Webpack 加载器进行自定义文件转换
Turbopack 现在附带对某些 webpack 加载器的支持和兼容性。这意味着您可以使用 Webpack 生态系统中的许多加载器将不同类型的文件转换为 JavaScript。支持诸如 @mdx-js/loader
、@svgr/webpack
和 babel-loader
等加载器。了解更多 关于自定义 Turbopack。
例如,使用 experimental.turbo.loaders
为每个文件扩展名配置加载器列表
module.exports = {
experimental: {
turbo: {
loaders: {
'.md': [
{
// Option format
loader: '@mdx-js/loader',
options: {
format: 'md',
},
},
],
'.svg': ['@svgr/webpack'],
},
},
},
};
查看 使用加载器的 Turbopack 示例 以获取完整示例。
Webpack 风格的 Resolve 别名
现在可以配置 Turbopack 以通过别名修改模块解析,类似于 webpack 的 resolve.alias
。通过 experimental.turbo.resolveAlias
进行配置
module.exports = {
experimental: {
turbo: {
resolveAlias: {
underscore: 'lodash',
mocha: { browser: 'mocha/browser-entry.js' },
},
},
},
};
Next.js 缓存
Next.js 13.2 引入了新的 Next.js 缓存(Beta 版),它是 ISR 的演进,解锁了以下功能:
- 组件级别的渐进式 ISR
- 无需网络请求即可更快地刷新
- 更快地将代码更改重新部署到静态页面
对于完全静态的页面,ISR 的工作方式与今天相同。对于具有更精细数据获取(混合静态和动态)的页面,Next.js 缓存使用更精细的临时缓存。
借助 React 服务端组件的基础以及 Next.js App Router (app
) 中的并置数据获取,您现在可以将静态或动态数据与其消费组件一起封装。
export default async function Page() {
const [staticData, dynamicData, revalidatedData] = await Promise.all([
// Cached until manually invalidated
fetch(`https://...`),
// Refetched on every request
fetch(`https://...`, { cache: 'no-store' }),
// Cached with a lifetime of 10 seconds
fetch(`https://...`, { next: { revalidate: 10 } }),
]);
return <div>...</div>;
}
在使用 App Router 进行本地开发时,您现在将在 next dev
中看到与生产环境 next start
相同的缓存行为。当任何服务端组件或数据加载代码发生更改时,这提高了 Fast Refresh 的速度。
使用 Next.js 缓存,您的应用程序控制缓存,而不是第三方 API。这与 cache-control
标头不同,在 cache-control
标头中,上游控制值的缓存时间。
带有 Vercel 缓存 API 的 Next.js 缓存
Vercel 上的 Next.js 为您提供框架定义的基础设施。您编写应用程序代码,例如使用 fetch
进行组件级数据获取,我们为您搭建全球分布式基础设施,无需额外的工作。
新的 Next.js 缓存使更改代码独立于更改数据。这可以大大加快静态页面的重新部署,因为这些页面的生成可以使用现有缓存。
这个新的 Vercel 缓存 API 旨在与任何框架一起使用,但与 Next.js 缓存具有原生集成。了解更多关于 ISR 如何演变为 Next.js 缓存的信息,以及部署到 Vercel 时 Next.js 缓存的工作原理。
自托管时的 Next.js 缓存
自托管时,使用 LRU 缓存,默认大小为 50 MB。默认情况下,所有缓存条目都会自动写入磁盘。如果节点具有相同的缓存键,则此文件系统缓存可以在节点之间共享,类似于 今天的 ISR 的工作方式。
对于希望进一步自定义和修改 Next.js 缓存核心的开发人员,他们可以修改底层缓存键,并更改缓存条目的持久化方式和位置,包括完全禁用持久化。
其他改进
- 字体: 继令人难以置信的社区采用之后,
@next/font
现在作为next/font
内置于 Next.js 中。这意味着您不再需要单独安装@next/font
。了解更多。 - 字体: 基于社区反馈,
next/font
的默认font-display
属性已从optional
更改为font-display: swap
。 - 性能: 优化了构建过程以使用更少的内存,在我们的测试中节省了约 550MB(PR)。
- 性能: 避免多次加载项目配置,在我们的测试中平均加快了约 400 毫秒的构建速度(PR)。
- 性能: 优化了错误组件,在不更改样式的情况下减少了 0.4kb 的 HTML 有效负载(PR)。
- 性能: 将边缘捆绑包大小减少了约 130KB,几乎是原来的一半大小,以进一步减小部署到 Vercel 等边缘环境时的冷启动大小(PR)。
- 安全: 添加了配置
images.contentDispositionType: "attachment"
,以便在直接访问 Image Optimization API 时强制下载图像(PR)。
社区
Next.js 是超过 2,500 位个人开发者、谷歌和 Meta 等行业合作伙伴以及 Vercel 核心团队共同努力的成果。Next.js 每周 npm 下载量超过 390 万次,GitHub Star 数超过 10 万,是构建 Web 的最流行方式之一。
加入我们的社区:GitHub Discussions、Reddit 和 Discord。
本次发布由以下团队成员带来:
- Next.js 团队:Balazs、Hannes、Jan、Jiachi、Jimmy、JJ、Josh、Sebastian、Shu、Steven、Tim、Wyatt 和 Andrew。
- Turbopack 团队:Alex、Donny、Justin、Leah、LongYinan、Maia、OJ、Tobias 和 Will。
以及以下贡献者:@timneutkens, @loettz, @okcoker, @clive-h-townsend, @shuding, @JanKaifer, @sepiropht, @hanneslund, @huozhi, @aralroca, @balazsorban44, @cristobaldominguez95, @vinaykulk621, @Brooooooklyn, @feedthejim, @samsisle, @MarDi66, @styfle, @therealrinku, @sebmarkbage, @cravend, @hu0p, @kdy1, @ijjk, @juzhiyuan, @IvanKiral, @LukeSchlangen, @wojtekolek, @samdenty, @Josehower, @bennettdams, @SCG82, @mike-plummer, @kwonoj, @David0z, @denchance, @joulev, @wbinnssmith, @alexkirsz, @UnknownMonk, @leerob, @sairajchouhan, @imranbarbhuiya, @jomeswang, @ductnn, @thomasballinger, @chibicode, @jridgewell, @sreetamdas, @Juneezee, @SukkaW, @wyattjoh, @michaeloliverx, @cattmote, @joefreeman, @valentincostam, @qrohlf, @ossan-engineer, @rishabhpoddar, @vasucp1207, @Schniz, @andrii-bodnar, @gergelyke, @abstractvector, @wherehows, @BrodaNoel, @taep96, @abe1272001, @0xadada, @nbouvrette, @teobler, @lubakravche, @molebox, 和 @hiddenest。