2023年2月23日星期四
Next.js 13.2
发布者Next.js 13.2 包含 App Router (app) 的重大改进,为稳定性做准备。
- 内置 SEO 支持:新的元数据 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通过新的元数据 API 内置 SEO 支持
Next.js 从一开始就被设计为支持搜索引擎优化。
提供预渲染的 HTML 内容不仅有助于改善搜索引擎的索引,还可以提高应用程序的性能。虽然 Next.js 在许多版本中都为修改应用程序中的元数据 (next/head) 提供了简单的 API,但我们希望重新设计和增强您使用 App Router (app) 进行搜索引擎优化的方式。
新的元数据 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。
例如,您可以通过元数据定义开放图谱图像。
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 }) {}元数据 API 在 13.2 版本中适用于 App Router (app),取代了之前的 head.js 特殊文件。它不适用于 pages 目录。
了解有关 SEO 的更多信息或查看元数据 API 参考。我们要感谢 next-seo 在社区包方面所做的工作以及对初始 API 设计的反馈。
自定义路由处理器
App Router (app) 原始 Beta 版本缺少的一部分是 API 路由,它存在于 pages/api 目录中。我们希望借此机会创建一个新颖、更现代的 API 路由版本,并将其深度集成到 app 的新路由系统中。
路由处理器允许您使用 Web 请求和响应 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 for Server Components
MDX 是 Markdown 的超集,允许您直接在 Markdown 文件中编写 JSX。它是一种强大的方式,可以在内容中添加动态交互性和嵌入 React 组件。
使用 13.2 版本,您现在可以完全使用 React 服务器组件来处理 MDX——这意味着更少的客户端 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 服务器组件的支持。
Rust MDX 解析器
作为启用服务器组件 MDX 的一部分,我们还使用 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;此功能现已推出测试版。暂不支持 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 ... - 改进了快速刷新可靠性和错误恢复
- 改进了 CSS 优先级处理
- 改进了编译时评估
我们还修复了许多错误并提高了稳定性,同时在我们一些最大的内部 Next.js 应用程序和早期 Vercel 客户中对 Turbopack 进行了内部测试。
使用 Webpack Loaders 进行自定义文件转换
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 风格的解析别名
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 生产环境相同的缓存行为。这提高了在任何服务器组件或数据加载代码更改时的快速刷新速度。
使用 Next.js 缓存,您的应用程序控制缓存——而不是第三方 API。这与 cache-control 标头不同,后者由上游控制值的缓存时间。
Next.js Cache 与 Vercel Cache API
Next.js on Vercel 为您提供框架定义的 инфраструктура。您编写应用程序代码,例如使用 fetch 进行组件级别数据获取,我们无需额外工作即可为您搭建全球分布式基础设施。
新的 Next.js 缓存使更改代码独立于更改数据。这可以大大加快静态页面的重新部署,因为这些页面的生成可以使用现有缓存。
这个新的 Vercel 缓存 API 旨在与任何框架配合使用,但与 Next.js 缓存原生集成。了解更多关于 ISR 如何演变为 Next.js 缓存的信息,以及当部署到 Vercel 时 Next.js 缓存的工作原理。
自托管时的 Next.js 缓存
在自托管时,使用 LRU 缓存,默认大小为 50MB。所有缓存条目默认自动写入磁盘。如果这些节点具有相同的缓存键,则此文件系统缓存可以在节点之间共享,类似于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",以强制在直接访问图像优化 API 时下载图像(PR)。
社区
Next.js 是 2500 多名独立开发者、Google 和 Meta 等行业合作伙伴以及 Vercel 核心团队共同努力的成果。Next.js 每周有超过 390 万次 npm 下载和 100,000 多个 GitHub 星标,是构建 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。