大家好,我是Echa。
好消息,2023年5月5号 Next.js 官方正式发布 v13.4 版本。距离上个Next.js 13.3 版本(2023年4月7号),只有短短28 天时间。 从侧面说明了Next.js 研发团队还是相当给力的。但其Github仓库的 star 数已超过 106k,并且在全球拥有超过 106w名用户。Next.js 官方研发团队真厉害,给咱们开发人员带来了很多方便,小编举起大拇指点赞。
下面小编带着大家详细了解一下 Next.js 13.4版本更新内容。
Next.js 13.4是一个基础版本,标志着应用路由器的稳定性:
- 应用程序路由器(稳定):
- React服务器组件
- 嵌套管线和布局
- 简化的数据获取
- 流式处理和暂停
- 内置SEO支持
- Turbopack(Beta):您的本地开发服务器,速度更快,稳定性更强
- 服务器操作(Alpha):使用零客户端JavaScript在服务器上更改数据
自从六个月前Next.js 13发布以来,官方一直专注于为Next.js-App Router的未来奠定基础,这种基础可以在不进行不必要的破坏性更改的情况下逐步采用。
执行下面命令更新最新版体验
npm i next@latest react@latest react-dom@latest eslint-config-next@latest
next.js App Router
官方在2016年发布了Next.js,以提供一种简单的服务器渲染React应用程序的方式,我们的目标是创建一个更动态、更个性化、更全球化的网络。
在最初的公告中,我们分享了Next.js的一些设计原则:
- 零点设置。将文件系统用作API
- 只有JavaScript。一切都是函数
- 自动服务器渲染和代码拆分
- 数据获取由开发人员决定
Next.js现在已经六岁了。官方保留了最初的设计原则,随着Next.js被更多的开发人员和公司采用,我们一直在对框架进行基础升级,以更好地实现这些原则。
官方一直在开发下一代next.js,现在有了13.4,下一代已经稳定并可以采用了。这篇文章将分享更多关于我们应用路由器的设计决策和选择。
零点设置。将文件系统用作API
基于文件系统的路由一直是Next.js的核心功能。在我们最初的帖子中,我们展示了这个从单个React组件创建路由的例子:
// Pages Router
// pages/about.js
import react from 'react';
export default () => <h1>About us</h1>;
没有其他可配置的内容。把一个文件放在pages/Next.js路由器会处理剩下的文件。我们仍然喜欢这种简单的路由。但随着框架使用量的增长,开发人员希望使用它构建的接口类型也在增加。
开发人员要求改进对定义布局的支持,将UI嵌套为布局,并在定义加载和错误状态方面具有更大的灵活性。在现有的Next.js路由器上进行改造并不是一件容易的事。
框架的每一部分都必须围绕路由器进行设计。页面转换、数据获取、缓存、更改和重新验证数据、流式传输、设置内容样式等等。
为了使我们的路由器与流媒体兼容,并解决这些对增强布局支持的请求,我们开始构建新版本的路由器。
这是我们首次发布Layouts RFC后的亮点。
// New: App Router ✨
// app/layout.js
export default function rootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</HTML>
);
}
// app/page.js
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
比你在这里看到的更重要的是你没有看到的。这个新的路由器(可以通过应用程序/目录逐步采用)有一个完全不同的架构,建立在React Server Components和Suspense的基础上。
这个基础使我们能够删除最初为扩展React原语而开发的特定于Next.js的API。例如,您不再需要使用自定义_app文件来自定义全局共享布局:
// Pages Router
// pages/_app.js
// This "global layout" wraps all routes. There's no way to
// compose other layout components, and you cannot fetch global
// data from this file.
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
使用Pages Router,布局无法组合,数据获取也无法与组件共存。有了新的应用程序路由器,这一点现在得到了支持。
// New: App Router ✨
// app/layout.js
//
// The root layout is shared for the entire application
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
// app/dashboard/layout.js
//
// Layouts can be nested and composed
export default function DashboardLayout({ children }) {
return (
<section>
<h1>Dashboard</h1>
{children}
</section>
);
}
对于Pages Router,_document用于自定义来自服务器的初始负载。
// Pages Router
// pages/_document.js
// This file allows you to customize the <html> and <body> tags
// for the server request, but adds framework-specific features
// rather than writing HTML elements.
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
使用App Router,您不再需要从Next.js导入<Html>、<Head>和<Body>。相反,您只需使用React。
// New: App Router ✨
// app/layout.js
//
// The root layout is shared for the entire application
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
有机会构建一个新的文件系统路由器也是解决我们路由系统中许多其他相关功能请求的合适时机。例如:
- 以前,您只能从_app.js中的外部npm包(如组件库)导入全局样式表。这是一种不太理想的开发人员体验。使用App Router,您可以在任何组件中导入(并托管)任何CSS文件。
- 以前,选择使用Next.js进行服务器端渲染(通过getServerSideProps)意味着在整个页面水合之前,与应用程序的交互将被阻止。通过App Router,我们重构了架构,使其与React Suspense深度集成,这意味着我们可以选择性地对页面的部分进行水合,而不会阻止UI中的其他组件进行交互。内容可以立即从服务器流式传输,从而提高页面的加载性能。
路由器是Next.js工作的核心。但这与路由器本身无关,而是它如何集成框架的其余部分,如数据获取。
只有JavaScript。一切都是函数
Next.js和React开发人员希望编写JavaScript和TypeScript代码,并共同组成应用程序组件。来自我们的原始帖子:
import React from 'react';
import Head from 'next/head';
export default () => (
<div>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<h1>Hi. I'm mobile-ready!</h1>
</div>
);
这个组件封装了可以在应用程序的任何地方重用和组合的逻辑。与文件系统路由相结合,这意味着可以轻松地开始构建React应用程序,就像编写JavaScript和HTML一样。
例如,如果您想获取一些数据,那么Next.js的原始版本如下所示:
import React from 'react';
import 'isomorphic-fetch';
export default class extends React.Component {
static async getInitialProps() {
const res = await fetch('https://api.company.com/user/123');
const data = await res.json();
return { username: data.profile.username };
}
}
随着采用率的提高和框架的成熟,我们探索了新的数据获取模式。
getInitialProps同时运行服务器和客户端。这个API扩展了React组件,允许您做出承诺并将结果转发给组件的道具。
虽然getInitialProps今天仍然有效,但我们随后根据客户反馈迭代了下一代数据获取API:getServerSideProps和getstaticProps。
// Generate a static version of the route
export async function getStaticProps(context) {
return { props: {} };
}
// Or dynamically server-render the route
export async function getserverSideProps(context) {
return { props: {} };
}
这些API更清楚地表明了代码在客户端或服务器上的运行位置,并允许Next.js应用程序自动进行静态优化。此外,它允许静态导出,使Next.js能够部署到不支持服务器的地方(例如AWS S3 bucket)。
然而,这不仅仅是“JavaScript”,我们希望更接近我们最初的设计原则。
自从Next.js创建以来,我们一直与Meta的React核心团队密切合作,在React原语的基础上构建框架功能。我们的合作伙伴关系,加上React核心团队多年的研发,为Next.js带来了通过最新版本的React架构(包括服务器组件)实现我们目标的机会。
使用AppRouter,您可以使用熟悉的异步和等待语法来获取数据。没有新的API可供学习。默认情况下,所有组件都是React服务器组件,因此数据获取在服务器上安全地进行。例如:
// app/page.js
export default async function Page() {
const res = await fetch('https://api.example.com/...');
// The return value is *not* serialized
// You can use Date, Map, Set, etc.
const data = res.json();
return '...';
}
至关重要的是,实现了“数据获取由开发人员决定”的原则。您可以获取数据并编写任何组件。不仅是第一方组件,还有服务器组件生态系统中的任何组件,比如Twitter嵌入的react tweet,它被设计成与服务器组件集成并完全在服务器上运行。
// app/page.js
import { Tweet } from 'react-tweet';
export default async function Page() {
return <Tweet id="790942692909916160" />;
}
由于路由器与React Suspense集成在一起,您可以在加载部分内容时更流畅地显示回退内容,并根据需要逐步显示内容。
// app/page.js
import { Suspense } from 'react';
import { PostFeed, Weather } from './components';
export default function Page() {
return (
<section>
<Suspense fallback={<p>Loading feed...</p>}>
<PostFeed />
</Suspense>
<Suspense fallback={<p>Loading weather...</p>}>
<Weather />
</Suspense>
</section>
);
}
此外,路由器将页面导航标记为转换,从而使路由转换可以中断。
自动服务器渲染和代码拆分
当我们创建Next.js时,开发人员手动配置webpack、babel和其他工具来运行React应用程序仍然很常见。添加进一步的优化,如服务器渲染或代码拆分,通常不会在自定义解决方案中实现。Next.js和其他React框架创建了一个抽象层来实现和强制这些最佳实践。
基于路由的代码拆分意味着页面/目录中的每个文件都将被代码拆分为自己的JavaScript捆绑包,这有助于减少文件系统并提高初始页面加载性能。
这对服务器渲染的应用程序以及使用Next.js的单页应用程序都是有益的,因为后者通常在应用程序启动时加载一个大型JavaScript捆绑包。然而,为了实现组件级代码拆分,开发人员需要使用next/dynamic来动态导入组件。
// app/page.tsx
import dynamic from 'next/dynamic';
const DynamicHeader = dynamic(() => import('../components/header'), {
loading: () => <p>Loading...</p>,
});
export default function Home() {
return <DynamicHeader />;
}
对于应用程序路由器,服务器组件不包含在浏览器的JavaScript捆绑包中。默认情况下,客户端组件会自动进行代码分割(使用Next.js中的webpack或Turbopack)。此外,由于整个路由器架构都启用了流式传输和Suspense,因此您可以逐步将部分UI从服务器发送到客户端。
例如,您可以使用条件逻辑对整个代码路径进行代码拆分。在本例中,您不需要为注销的用户加载仪表板的客户端JavaScript。
// app/layout.tsx
import { getUser } from './auth';
import { Dashboard, Landing } from './components';
export default async function Layout() {
const isLoggedIn = await getUser();
return isLoggedIn ? <Dashboard /> : <Landing />;
}
Turbopack (Beta)
Turbopack是我们正在通过Next.js测试和稳定的新bundler,它有助于加快本地迭代,同时处理您的Next.jss应用程序(通过下一个dev-turbo),并很快完成您的生产构建(下一个构建-turbo)。
自从Next.js 13中的alpha版本发布以来,我们看到了采用率的稳步增长,因为我们一直在努力修补漏洞并增加对缺失功能的支持。我们一直在Vercel.com上对Turbopack进行跟踪,许多Vercel客户都在运营大型Next.js网站,以收集反馈并提高稳定性。我们非常感谢社区在测试和向我们的团队报告错误方面的支持。
六个月后,我们已经准备好进入测试阶段。
Turbopack还没有与webpack和Next.js完全相同的功能。我们正在跟踪本期对这些功能的支持。然而,现在应该支持大多数用例。我们测试版的目标是继续解决因采用率增加而留下的漏洞,并为未来版本的稳定性做好准备。
我们在改进Turbopack的增量引擎和缓存层方面的投资不仅将加快当地的开发,而且很快就会建立生产。请继续关注未来的Next.js版本,在该版本中,您将能够运行下一个构建——用于即时构建的turbo。
今天在Next.js 13.4中试用Turbopack测试版,下一个开发版本是turbo。
Server Actions (Alpha)React生态系统在表单、管理表单状态以及缓存和重新验证数据方面进行了大量创新和探索。随着时间的推移,React对其中一些模式变得更加固执己见。例如,对于形状状态,建议使用“非受控组件”。
当前的解决方案生态系统要么是可重用的客户端解决方案,要么是构建在框架中的原语。到目前为止,还没有一种方法来组合服务器突变和数据基元。React团队一直在研究突变的第一方解决方案。
我们很高兴宣布支持Next.js中的实验性服务器操作,使您能够改变服务器上的数据,直接调用函数,而无需创建中间API层。
// app/post/[id]/page.tsx (Server Component)
import kv from './kv';
export default function Page({ params }) {
async function increment() {
'use server';
await kv.incr(`post:id:${params.id}`);
}
return (
<form action={increment}>
<button type="submit">Like</button>
</form>
);
}
通过服务器操作,您可以实现强大的服务器优先数据突变、更少的客户端JavaScript和逐步增强的表单。
// app/dashboard/posts/page.tsx (Server Component)
import db from './db';
import { redirect } from 'next/navigation';
async function create(formData: FormData) {
'use server';
const post = await db.post.insert({
title: formData.get('title'),
content: formData.get('content'),
});
redirect(`/blog/${post.slug}`);
}
export default function Page() {
return (
<form action={create}>
<input type="text" name="title" />
<textarea name="content" />
<button type="submit">Submit</button>
</form>
);
}
Next.js中的服务器操作是为与数据生命周期的其余部分进行深度集成而设计的,包括Next.js缓存、增量静态再生(ISR)和客户端路由器。
通过新的API重新验证数据revalidatePath和revalidateTag意味着在一次网络往返中可以发生更改、重新呈现页面或重定向,从而确保在客户端上显示正确的数据,即使上游提供商速度较慢。
// app/dashboard/posts/page.tsx (Server Component)
import db from './db';
import { revalidateTag } from 'next/cache';
async function update(formData: FormData) {
'use server';
await db.post.update({
title: formData.get('title'),
});
revalidateTag('posts');
}
export default async function Page() {
const res = await fetch('https://...', { next: { tags: ['posts'] } });
const data = await res.json();
// ...
}
服务器操作被设计为可组合的。React社区中的任何人都可以构建和发布服务器操作,并在生态系统中分发它们。就像服务器组件一样,我们对客户端和服务器的可组合原语的新时代感到兴奋。
服务器操作现在可以在alpha中使用Next.js 13.4。通过选择使用服务器操作,Next.js将使用React的实验发布通道。
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
};
module.exports = nextConfig;
最后
一台电脑,一个键盘,尽情挥洒智慧的人生;几行数字,几个字母,认真编写生活的美好;
一 个灵感,一段程序,推动科技进步,促进社会发展。
创作不易,喜欢的老铁们加个关注,点个赞,打个赏,后面会不定期更新干货和技术相关的资讯,速速收藏,谢谢!你们的一个小小举动就是对小编的认可,更是创作的动力。