2023年2月23日,星期四
Next.js 13.2
发布者Next.js 13.2 包含对 App 路由器 (app
) 的重大改进,为稳定性做好准备
- 内置 SEO 支持: 新的元数据 API 用于设置静态和动态
meta
标签。 - 路由处理器: 基于 Web
Request
和Response
构建的自定义请求处理器。 - 服务器组件的 MDX: 在 Markdown 中使用 React 组件,仅限服务器端。
- Rust MDX 解析器: 使用全新的 Rust 插件加快 Markdown 解析速度。
- 改进的错误覆盖层: 分离 Next.js 和 React 堆栈跟踪,以提高可读性。
- 静态类型链接(测试版): 使用
next/link
和 TypeScript 防止链接失效。 - Turbopack 改进(Alpha 版): 与 Webpack 加载程序兼容并提供改进的支持。
- Next.js 缓存(测试版): 渐进式 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 路由器 (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 路由器 (app
),取代了以前的 head.js
特殊文件。它不适用于 pages
目录。
详细了解 SEO 或查看元数据的 API 参考。我们要感谢next-seo 他们在社区包上的工作以及对初始 API 设计的反馈。
自定义路由处理器
App 路由器 (app
) 的原始测试版发布中缺少的部分之一是 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 路由器 (app
),使用 route.ts
特殊文件。它们不适用于 pages
目录,因为它们是 API 路由的替代品。
详细了解路由处理器 或查看 API 参考。我们要感谢 SvelteKit 提供的先前技术和灵感。
服务器组件的 MDX
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 服务器组件的支持。
了解有关如何使用服务器组件设置 MDX 的更多信息 或 部署我们的示例。
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 路由器以及 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 加载器进行自定义文件转换
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 缓存(测试版),它是 ISR 的演变,它可以解锁
- 组件级别的渐进式 ISR
- 无需网络请求即可更快地刷新
- 更快地重新部署对静态页面的代码更改
对于完全静态的页面,ISR 的工作方式与今天相同。对于具有更细粒度数据获取的页面(混合静态和动态),Next.js 缓存使用更细粒度、短暂的缓存。
借助 Next.js App 路由器 (app
) 中的 React 服务器组件和协同数据获取的基础,你现在可以将静态或动态数据与其使用组件一起封装。
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 路由器进行本地开发时,你现在将在 next dev
中看到与 next start
生产环境中相同的缓存行为。这提高了任何服务器组件或数据加载代码更改时的快速刷新速度。
借助 Next.js 缓存,您的应用可以控制缓存,而不是第三方 API。这与cache-control
头部不同,在 cache-control
头部中,上游控制缓存值的时长。
Next.js 缓存与 Vercel 缓存 API
Vercel 上的 Next.js 为您提供了框架定义的基础设施。您可以编写应用程序代码,例如使用fetch
进行组件级数据获取,我们无需任何额外操作即可为您构建全局分布式基础设施。
新的 Next.js 缓存使代码更改与数据更改相互独立。这可以极大地加快静态页面的重新部署速度,因为这些页面的生成可以使用现有的缓存。
这个新的 Vercel 缓存 API 旨在与任何框架一起使用,但与 Next.js 缓存进行了原生集成。 了解有关 ISR 如何演变为 Next.js 缓存的更多信息,以及 Next.js 缓存部署到 Vercel 时如何工作。
自托管时的 Next.js 缓存
自托管时,使用 LRU 缓存,默认为 50 MB。默认情况下,所有缓存条目都会自动写入磁盘。如果节点具有相同的缓存键,则此文件系统缓存可以在节点之间共享,类似于ISR 的当前工作方式。
对于希望进一步自定义和修改 Next.js 缓存核心的开发人员,他们可以修改底层缓存键并更改缓存条目的持久化方式和位置,包括完全禁用持久化。
其他改进
- 字体:在社区取得令人难以置信的采用率后,
@next/font
现在已内置到 Next.js 中,成为next/font
。这意味着您不再需要单独安装@next/font
。 了解更多。 - 字体:根据社区反馈,
next/font
的默认font-display
属性已更改为font-display: swap
,而不是optional
。 - 性能:优化了构建过程以使用更少的内存,在我们的测试中节省了约 550 MB(PR)。
- 性能:避免多次加载项目配置,导致我们的测试中构建速度平均加快约 400 毫秒(PR)。
- 性能:优化了错误组件,在不更改样式的情况下减少了 0.4kb 的 HTML 负载(PR)。
- 性能:将边缘包大小减少了约 130KB,几乎减少了一半,以进一步减少部署到 Vercel 等边缘环境时的冷启动大小(PR)。
- 安全性:添加了配置
images.contentDispositionType: "attachment"
,以在直接访问图像优化 API 时强制下载图像(PR)。
社区
Next.js 是超过 2500 名独立开发人员、谷歌和 Meta 等行业合作伙伴以及我们在 Vercel 的核心团队共同努力的结果。Next.js 每周有超过 390 万次 npm 下载量和超过 100,000 个 GitHub 星标,是构建 Web 的最流行方式之一。
加入 GitHub 讨论、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。