likes
comments
collection
share

[译]Next.js 13.4|Next.js 新模式已发布稳定版本

作者站长头像
站长
· 阅读数 23

本文为翻译文章,原文链接:nextjs.org/blog/next-1…

Next.js 13.4 是一个基础版本,标志着 App Router 模式的稳定:

自六个月前发布了 Next.js 13 以来,Next.js 团队一直致力于以可增量采用的方式构建 Next.js 的未来基础—— app 路由(App Router)模式,而无需不必要的破坏性更改。(意味着可以 pages 路由 和 app 路由一起使用)

今天,随着 13.4 的发布,您现在可以开始采用 App Router 开发生产应用。

npm i next@latest react@latest react-dom@latest eslint-config-next@latest

Next.js App Router

Next.js 在 2016 年发布了 Next.js,旨在为 React 应用程序提供一种简单的服务器渲染方式,我们的目标是创建一个更具动态性、个性化和全球性的Web。

在最初的发布文章中,我们分享了Next.js的一些设计原则:

  • 零配置,使用文件系统作为API
  • 只有JavaScript,一切皆是函数
  • 自动服务器渲染和代码拆分
  • 数据获取由开发人员决定

Next.js 现在已经六年了。我们最初的设计原则一直保持不变——随着越来越多的开发人员和公司采用Next.js,我们一直在努力对框架进行基础升级,以更好地实现这些原则。

我们一直在开发 Next.js 的下一代版本,而今天的 13.4 版本已经稳定并准备好被采用了。本文将分享更多关于我们的设计决策和应用程序路由器的选择。

零配置,使用文件系统作为API

基于文件系统的路由(File-system based routing)一直是Next.js的核心功能。在我们最初的文章中,我们展示了从单个React组件创建路由的示例:

// Pages Router
// pages/about.js

import React from 'react';
export default () => <h1>About us</h1>;

没有其他需要配置的东西,将文件放在 pages/ 文件夹中即可,Next.js 路由会处理其余的部分。我们仍然喜欢路由的这种简单性,但是随着框架的使用增加,开发人员希望使用它构建更多类型的界面。

开发人员要求改进定义布局的支持,将 UI 组件作为布局嵌套,以及在定义加载和错误状态方面具有更多灵活性,这对于现有的 Next.js 路由不是一个容易的事情。

框架的每个部分都必须围绕路由设计,主要包含页面切换、数据获取、缓存、数据变更和重新验证、流传输、内容样式等等。

为了使我们的路由器兼容流传输,并解决这些对布局增强支持的请求,我们决定构建一个新版本的路由器。

这就是我们在发布我们的 布局 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>;
}

比你在这里看到的更重要的是你没有看到的。这个新的路由器(可以通过app/目录逐步采用)具有完全不同的架构,建立在 React Server ComponentsSuspense 的基础上。

这个基础使我们能够删除最初为扩展 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} />;
}

在旧的页面路由器中,不能组合布局,也不能将数据获取与组件放在同一个地方。现在,新的 App 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 直接编写 html 内容。

// 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 文件。
  • 以前,通过 getServerSideProps 来选择使用 Next.js 进行服务器端渲染,这意味着在整个页面在被 hydrate 之前无法与应用程序交互。使用 App Router,我们已经重构了架构,使其与 React Suspense 深度集成,这意味着我们可以有选择地 hydrate 页面的某些部分内容,而不会阻止 UI 中的其他组件进行交互。内容可以从服务器流式传输,从而改善页面的感知加载性能。

Router 是 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>
);

在未来的 Next.js 版本中,我们添加了一个 DX 改进,可以为您自动导入 React。

这个组件封装了可以在应用程序的任何地方重用和组合的逻辑。配合文件系统路由,这意味着可以使用一种简单的方法来开始构建 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 };
  }
}

在未来的 Next.js 版本中,我们添加了 DX 改进,它会自动注入 fetch 的 polyfill,因此您不需要导入 “isomorphic-fetch” 或 “node-fetch”,并且可以在客户端和服务器上同时使用 “fetch API”。

随着应用场景的增长和框架的发展,我们探索了数据获取的新模式。

getInitialProps 同时在服务器端和客户端上运行。这个 API 扩展了 React 组件,允许你创建一个Promise,并将结果转发给组件的 props

尽管 getInitialProps 如今仍然有效,但我们基于客户反馈迭代了下一代数据获取API: getServerSidePropsgetStaticProps

// 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存储桶)。

然而,这并不是“仅仅是 JavaScript”,我们希望更贴近我们最初的设计原则。

自从Next.js创建以来,我们一直与 Meta 的 React 核心团队密切合作,在 React 原语之上构建框架功能。我们的合作,再加上 React 核心团队多年的研究和开发,为 Next.js 通过最新版本的 React 架构实现我们的目标提供了机会,包括 Server Components

使用 App Router,你可以使用熟悉的 async 和 await 语法 获取数据。没有需要学习的新 API。默认情况下,所有组件都是 React Server Components,因此数据获取在服务器端安全地进行。例如:

// 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 '...';
}

重要的是,“数据获取取决于开发人员” 的原则得以实现。您可以获取数据并组成任何组件。不仅是第一方组件,而且是 Server Components 生态系统中的任何组件,比如与 Server Components 集成并完全在服务器上运行的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>
  );
}

此外,路由器将页面导航标记为 transitions,从而使路由切换可中断。

自动服务器渲染和代码拆分

当我们创建应用时,开发人员通常会手动配置 webpack、babel和其他工具来运行 React 应用程序。而添加进一步的优化,例如服务器渲染或代码拆分,通常不会在自定义解决方案中实现。Next.js 以及其他 React 框架创建了一个抽象层来实现和强制执行这些最佳实践。

基于路由的代码拆分意味着您 pages/ 目录中的每个文件都将被拆分成自己的 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 />;
}

使用 App Router,服务器组件的代码不会包含在浏览器的 JavaScript bundle 包中。客户端组件 默认情况下会自动进行代码拆分 (在 Next.js 中使用 webpack 或 Turbopack 实现)。此外,由于整个路由器体系结构都启用了流传输和 Suspense,因此您可以逐步将部分 UI 从服务器发送到客户端。

例如,您可以使用条件逻辑对整个代码路径进行编码。在此示例中,您不需要为已注销的用户加载 Dashboard 的客户端 JavaScript。

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 测试和稳定的新打包工具,它可以通过next dev --turbo加快在 Next.js 应用程序上工作时的本地迭代速度,并很快支持生产构建(next build --turbo)。

自 Next.js 13 的alpha版本发布以来,我们已经看到了稳定的增长,因为我们致力于修补错误并添加对缺失功能的支持。我们一直在 Vercel.com 上使用 Turbopack,并与许多 Vercel 客户一起运营大型 Next.js 网站,以收集反馈并改善稳定性。我们非常感谢社区对我们团队的测试和错误报告的支持。

六个月后,我们准备进入beta阶段。

Turbopack 还没有与 webpack 和 Next.js 完全相同的功能。我们正在 this issue 中跟踪对这些功能的支持。但是,大多数用例现在应该得到支持。我们的目标是在此 beta 版中继续解决由于增加的使用而导致的剩余错误,并为将来的版本做好稳定性准备。

我们投资于改进 Turbopack 的增量引擎和缓存层,这不仅可以加快本地开发速度,还可以快速支持生产构建。敬请期待下一个 Next.js 版本,您将能够运行 next build --turbo 进行即时构建。

在 Next.js 13.4 中使用 next dev --turbo 尝试 Turbopack beta 版吧。

Server Actions (Alpha)

React 生态系统在表单、表单状态管理以及数据缓存和重新验证等方面看到了很多创新和思路探索。随着时间的推移,React 对其中一些模式变得更加有自己的意见。例如,推荐使用 非受控组件 来管理表单状态。

目前的解决方案生态系统要么是可重用的客户端解决方案,要么是内置在框架中的基础单元。到目前为止,还没有一种方法可以将服务器变更(Mutations)和数据原型结合起来。React 团队一直在为变更的第一方解决方案而努力。

我们很高兴在 Next.js 中宣布支持实验性的 Server Actions ,允许您在服务器上变更数据,直接调用函数而无需创建介于两者之间的 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>
  );
}

通过使用 Server Actions,您可以实现强大的服务器优先数据变更、更少的客户端 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” 重新验证数据意味着在 ** one network roundtrip ** 中可以发生更改,重新渲染页面或重定向,从而确保在客户端上显示正确的数据,即使上游提供商速度很慢。

通过新的 API revalidatePathrevalidateTag 重新验证数据意味着数据变更、重新渲染页面或重定向可以在 一次网络往返 中发生,从而确保客户端显示正确的数据,即使上游提供商速度很慢。

// 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();
  // ...
}

服务器操作(Server Actions)旨在可组合。React 社区中的任何人都可以构建和发布 Server Actions,并在生态系统中分发它们。就像服务器组件一样,我们对客户端和服务器的新的可组合原语时代感到兴奋。

Server Actions 现在可以在 Next.js 13.4 中的 alpha 版本中使用。通过选择使用 Server Actions,Next.js 将使用 React 的实验性版本通道。

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    serverActions: true,
  },
};

module.exports = nextConfig;

其他改进

  • 草稿模式:从您的无头 CMS 获取和呈现草稿内容。草稿模式适用于 pages 和 app 路由模式。我们增强和简化了现有的预览模式 API,该 API 仍适用于页面。预览模式不适用于应用程序,您应该使用草稿模式。

更多查看:nextjs.org/blog/next-1…

本篇文章结合AI进行翻译,但整篇文章都进行了检查,有问题欢迎指出。