你好!这是另一篇关于 next.js 的文章。最后,关于新版本!每个版本都包含一组新的、有趣的和有争议的功能。这个版本也不例外。然而,新版本的有趣之处并不在于它的新功能,而是在于 next.js 中优先级和组织的变化。是的,正如您可能从标题中猜到的那样,此版本的重要部分对于反思以前的错误很有价值。
从版本 8 左右开始,我就一直在使用 next.js。一直以来,我一直饶有兴趣地关注它的开发(有时并非没有失望)。最近,我发表了一系列关于与新的 App Router 作斗争的文章 - “Next.js App Router。通向未来的道路还是错误的转折”、“Next.js 缓存。礼物还是诅咒”、“为图书馆之神提供更多图书馆或我如何重新思考 i18n”。所有这些都是 next.js 之前版本的思想和功能开发非常薄弱的结果。正因为如此,我对新版本的兴趣有增无减。除此之外,人们还渴望了解框架中的变化向量。
在本文中,我不会详细讨论 App Router 或服务器组件是什么 - 这些在之前的文章中有详细描述。我们将只关注新版本和新变化。
注:文章反映了从作者角度来看最有趣的变化。它们与官方列表不同,因为作者是从框架中的提交和 PR 中选择的。
首先,介绍一下 next.js 内部开发流程的变化。框架团队首次发布了候选版本(RC 版本)。显然,他们这样做是因为 React.js 团队决定发布 React v19 RC。
通常,稳定版本中的 next.js 团队会平静地使用“Canary”版本分支中的 React(该分支被认为是稳定的,建议框架使用)。然而,这一次,他们决定采取不同的做法(剧透 - 没有白费)。
两个团队的计划都很简单 - 发布预发布版本,让社区检查问题,然后在几周内发布完整版本。
React.js 的候选版本发布已经过去了 6 个多月,但稳定版本仍未发布。 React.js 稳定版本的延迟发布也影响了 next.js 的计划。因此,与传统相反,他们在第 15 个版本已经开始工作的同时,总共发布了 15 个附加补丁版本(通常是 3-5 个补丁,然后发布一个版本)。这里值得注意的是,这些补丁版本并没有包含所有累积的更改,而只是解决了关键问题,这也偏离了 next.js 的通常流程。
next.js 中的基本发布流程是,所有内容都合并到金丝雀分支中,然后在某个时刻,该分支作为稳定版本发布。
然而,因此,next.js 团队决定与 React.js 版本解耦,在 React.js 稳定版本发布之前发布稳定版本的框架。
另一个非常有用的组织变革。最后,可以查看不同版本的文档。这就是为什么这如此重要:
首先,由于重大变化,更新 next.js 通常是一项相当具有挑战性的任务。事实上,这就是为什么版本 12 的下载量仍然超过 200 万次,版本 13 的下载量每月超过 400 万次(公平地说,版本 14 的下载量超过 2000 万次)。
因此,以前版本的用户需要特定于其版本的文档,因为新版本可能会重写一半。
另一个问题是 Next.js 本质上使用单个通道。文档也对其进行了更改。因此,金丝雀版本的更改描述立即出现在主要文档中。现在它们显示在“金丝雀”部分下。
一开始,我提到 Next.js 目前正在使用 React.js 的 RC 版本。但事实上,这并不完全正确,或者说不完全正确。事实上,Next.js 目前使用两种 React.js 配置:App Router 的第 19 个金丝雀版本和 Pages Router 的第 18 个版本。
有趣的是,有一次他们也想包含 Pages Router 的第 19 版,但后来又回滚了这些更改。现在,在稳定版本发布后,承诺全面支持 React.js 版本 19。
除此之外,新版本还将对服务器操作功能进行一些有用的改进(是的,React团队将它们重命名为):
我想我也会在本节中包含 Next.js 的新功能 - Form 组件。总的来说,它是 React-dom 中熟悉的形式,但有一些改进。如果成功提交表单涉及导航到另一个页面,则主要需要此组件。对于下一页,将预加载loading.tsx和layout.tsx抽象。
import Form from 'next/form' export default function Page() { return ( <Form action="/search">; {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" />; <button type="submit">Submit</button>; </Form>; ) }
在谈论 Next.js 时,我们不能忽视开发者体验。除了“更快、更高、更强”标准(我们稍后也会讨论)之外,还发布了一些有用的改进。
期待已久的对最新 ESLint 的支持。 Next.js 到目前为止还不支持 ESLint v9。尽管 eslint 本身 (v8) 及其一些子依赖项已被标记为已弃用,但情况仍然如此。这导致了一种不愉快的情况,项目基本上被迫保留已弃用的包。
错误界面略有改进(在 Next.js 中已经清晰方便):
添加了“静态指示器” - 页面一角的一个元素,显示页面已在静态模式下构建。
总的来说,这是一件小事,但有趣的是他们将其作为新的东西包含在关键更改中。 “预建”页面的指示器大约从版本 8 (2019) 开始就已经存在,本质上,他们只是稍微更新了它并针对 App Router 进行了调整。
还添加了包含调试信息的目录 - .next/diagnostics。它将包含有关构建过程和发生的所有错误的信息。目前尚不清楚这在日常使用中是否有用,但在解决 Vercel devrel 问题时肯定会使用它(是的,它们有时有助于解决问题)。
讨论完 DX,值得谈谈构建过程。还有 Turbopack。
以及该领域最大的新闻。 Turbopack 的开发模式现已完全完成! “Turbopack 100% 的现有测试均通过且没有错误”
现在Turbo团队正在开发生产版本,逐步进行测试和完善(目前完成约96%)
Turbopack 还添加了新功能:
import Form from 'next/form' export default function Page() { return ( <Form action="/search">; {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" />; <button type="submit">Submit</button>; </Form>; ) }
Turbopack 中的这些和其他改进“减少了 25-30% 的内存使用量”,并且“将大量页面的构建速度加快了 30-50%”。
重大的样式问题已得到修复。在版本 14 中,经常会出现导航过程中样式顺序被破坏的情况,导致样式 A 高于样式 B,反之亦然。这改变了它们的优先级,因此元素看起来不同。
下一个期待已久的改进。现在可以用 TypeScript 编写配置文件 - next.config.ts
const nextConfig = { experimental: { turbo: { treeShaking: true, memoryLimit: 1024 * 1024 * 512 // in bytes / 512MB }, }, }
另一个有趣的更新是重试静态页面构建。这意味着如果页面在构建时失败(例如,由于互联网问题) - 它将尝试再次构建。
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig;
总结本节,这是社区非常期望的功能 - 指定用于构建的其他文件的路径的能力。例如,使用此选项,您可以指定文件不位于应用程序目录中,而是位于 module/main、modules/invoices 等目录中。
但是,目前他们仅出于团队内部目的添加它。而在这个版本中,他们肯定不会呈现。展望未来,它将用于满足 Vercel 需求,或者他们将对其进行测试并在下一个版本中呈现。
Next.js 更新中最痛苦的部分 - API 更改。并且在这个版本中,还有重大更新。
几个内部框架 API 已变为异步 - cookies、headers、params 和 searchParams(所谓的动态 API)。
const nextConfig = { experimental: { staticGenerationRetryCount: 3, }, }
这是一个重大变化,但 Next.js 团队承诺所有这些功能都可以通过调用他们的 codemod 自动更新:
npx @next/codemod@canary next-async-request-api .
另一个变化,但可能与很多人无关。密钥 geo 和 ip 已从 NextRequest 中删除(用于中间件和 API 路由)。本质上,此功能仅在 Vercel 中有效,而在其他地方开发人员则制定了自己的方法。对于 Vercel,此功能将移至 @vercel/functions 包
还有一些更新:
import Form from 'next/form' export default function Page() { return ( <Form action="/search">; {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" />; <button type="submit">Submit</button>; </Form>; ) }
在我个人看来,这是 Next.js 最重要的变化发生的地方。最大的消息是 - 现在默认禁用缓存! 我不会详细讨论缓存问题,这在“Next.js 缓存。礼物还是诅咒”一文中主要介绍了。
让我们看看缓存中的所有主要变化:
const nextConfig = { experimental: { turbo: { treeShaking: true, memoryLimit: 1024 * 1024 * 512 // in bytes / 512MB }, }, }
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig;
这就是关于“历史误会”的问题。新的 API 也将出现在 Next.js 中。即所谓的动态I/O。目前还没有任何相关的文章,所以以下是作者根据改动的猜测。
动态 I/O 似乎是动态构建的高级模式。类似于 PPR(部分预渲染),或者更准确地说,它的补充。简而言之,部分预渲染是一种页面构建模式,其中大多数元素在构建时构建并缓存,而单个元素则针对每个请求构建。
因此,动态 I/O [可能] 最终确定了该逻辑的架构。它扩展了缓存功能,以便可以根据模式和使用地点精确地启用和禁用它(是否在“动态”块中)。
import Form from 'next/form' export default function Page() { return ( <Form action="/search">; {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" />; <button type="submit">Submit</button>; </Form>; ) }
除此之外,还添加了“使用缓存”指令。它将在 Nodejs 和边缘运行时中可用,显然,在所有服务器段和抽象中都可用。通过在函数或导出函数的模块顶部指定此指令 - 其结果将被缓存。该指令仅在启用dynamicIO时才可用。
const nextConfig = { experimental: { turbo: { treeShaking: true, memoryLimit: 1024 * 1024 * 512 // in bytes / 512MB }, }, }
另外,专门为了使用缓存,添加了方法cacheLife和cacheTag
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig;
cacheTag将用于使用revalidateTag进行重新验证,cacheLife将设置缓存生存期。对于cacheLife 值,您需要使用预设值之一。几个开箱即用的选项(“秒”,“分钟”,“小时”,“天”,“周”,“最大”),可以在 next.config.js 中指定其他选项:
const nextConfig = { experimental: { staticGenerationRetryCount: 3, }, }
可能是下一个版本的主要功能。如前所述,PPR 是一种页面构建模式,其中大多数元素在构建时组装并缓存,而单个元素则针对每个请求进行组装。同时,预构建的部分会立即发送到客户端,而其余部分则动态加载。
该功能本身是六个月前在候选版本中作为实验性 API 引入的。此 API 将保持这种状态,我们可能只会在版本 16 中看到它稳定(这很好,因为主要功能通常会在六个月到一年内过渡到稳定)。
关于更改。前面说过,主要是更新了工作原理。不过,从使用PPR的角度来看,这几乎没有什么影响。同时,它还获得了多项改进:
以前,配置中只有一个标志,但现在要启用 PPR,您需要指定“增量”。这样做显然是为了让逻辑更加透明 - 即使在 PPR 中,开发者也可以缓存内容,并且要更新它,您需要调用 revalidate 方法。
import { cookies } from 'next/headers'; export async function AdminPanel() { const cookieStore = await cookies(); const token = cookieStore.get('token'); // ... }
另外,之前PPR是针对整个项目启动的,但现在需要针对每个分段(布局或页面)启用:
const nextConfig = { images: { localPatterns: [ { pathname: '/assets/images/**', search: 'v=1', }, ], }, }
另一个变化是部分回退预渲染(PFPR)。正是由于这一改进,预构建的部分立即发送到客户端,而其余部分则动态加载。在此期间,会显示回调组件来代替动态元素。
import Form from 'next/form' export default function Page() { return ( <Form action="/search">; {/* On submission, the input value will be appended to the URL, e.g. /search?query=abc */} <input name="query" />; <button type="submit">Submit</button>; </Form>; ) }
Instrumentation 被标记为稳定的 API。检测文件允许用户挂钩 Next.js 服务器的生命周期。它适用于整个应用程序(包括 Pages Router 和 App Router 的所有部分)。
目前,instrumentation 支持以下钩子:
register - 初始化 Next.js 服务器时调用一次。它可用于与可观测性库(OpenTelemetry、datadog)集成或用于特定于项目的任务。
onRequestError - 为所有服务器错误调用的新挂钩。它可用于与错误跟踪库(Sentry)集成。
const nextConfig = { experimental: { turbo: { treeShaking: true, memoryLimit: 1024 * 1024 * 512 // in bytes / 512MB }, }, }
拦截器,也称为路由级中间件。它类似于一个成熟的[已经存在的]中间件,但与后者不同:
此外,当创建拦截器文件时,树中下面的所有页面都会变成动态的。
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { /* config options here */ }; export default nextConfig;
说到 Vercel,中间件现在将作为 CDN 级别的主要简单检查而有效(因此,例如,如果请求不被允许,则立即返回重定向),而拦截器将在服务器,执行全面的检查和复杂的操作。
然而,在自托管中,这样的划分显然效率较低(因为两个抽象都在服务器上工作)。仅使用拦截器可能就足够了。
覆盖提取、激进的缓存、大量错误以及忽略社区请求。 Next.js 团队做出了错误的决定,仓促发布,并且不顾社区反馈坚持自己的观点。花了将近一年的时间才认识到这些问题。直到现在,终于,人们感觉到该框架再次解决了社区问题。
另一方面,还有其他框架。一年前,在 React.js 演示中,似乎所有框架都将很快与 Next.js 相提并论。 React 开始较少提及 Next.js 作为主要工具,框架展示了即将推出的构建系统、对服务器组件和功能的支持以及一系列全局更改和集成。时间已经过去了,基本上,他们还没有达到那个地步。
当然,最终的结论要过一段时间才能得出,但目前看来,React.js 的变化并没有达到预期的框架水平,反而导致了 Next.js 的更大统治地位,框架之间的差异更大(因为服务器组件和操作的实现由框架自行决定)。
同时,OpenAI 改用 Remix(“因为它具有更高的稳定性和便利性”):
显然他们在 Next.js 发生重大变化之前就开始了
总的来说,在接下来的 stateofjs 和 stackoverflow 调查中,我们很可能会看到重大的洗牌。
制作人员
代码示例或其基础取自 next.js 文档、提交、PR 和 next.js 核心;
后记
如果您需要一个基于 MD 文件生成文档的工具 - 请查看 robindoc.com,如果您使用 next.js - 您可能会在 nimpl.tech 的解决方案中找到有用的东西。
以上是Next.js v——反思错误的详细内容。更多信息请关注PHP中文网其他相关文章!