首页 >web前端 >js教程 >Next.js v——反思错误

Next.js v——反思错误

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-10-26 04:06:02997浏览

你好!这是另一篇关于 next.js 的文章。最后,关于新版本!每个版本都包含一组新的、有趣的和有争议的功能。这个版本也不例外。然而,新版本的有趣之处并不在于它的新功能,而是在于 next.js 中优先级和组织的变化。是的,正如您可能从标题中猜到的那样,此版本的重要部分对于反思以前的错误很有价值。

从版本 8 左右开始,我就一直在使用 next.js。一直以来,我一直饶有兴趣地关注它的开发(有时并非没有失望)。最近,我发表了一系列关于与新的 App Router 作斗争的文章 - “Next.js App Router。通向未来的道路还是错误的转折”、“Next.js 缓存。礼物还是诅咒”、“为图书馆之神提供更多图书馆或我如何重新思考 i18n”。所有这些都是 next.js 之前版本的思想和功能开发非常薄弱的​​结果。正因为如此,我对新版本的兴趣有增无减。除此之外,人们还渴望了解框架中的变化向量。

在本文中,我不会详细讨论 App Router 或服务器组件是什么 - 这些在之前的文章中有详细描述。我们将只关注新版本和新变化。

注:文章反映了从作者角度来看最有趣的变化。它们与官方列表不同,因为作者是从框架中的提交和 PR 中选择的。

Next.js v15 发布

首先,介绍一下 next.js 内部开发流程的变化。框架团队首次发布了候选版本(RC 版本)。显然,他们这样做是因为 React.js 团队决定发布 React v19 RC。

通常,稳定版本中的 next.js 团队会平静地使用“Canary”版本分支中的 React(该分支被认为是稳定的,建议框架使用)。然而,这一次,他们决定采取不同的做法(剧透 - 没有白费)。

两个团队的计划都很简单 - 发布预发布版本,让社区检查问题,然后在几周内发布完整版本。

Next.js v— Reflecting on Mistakes


来自 React.js 核心团队开发人员的推文 https://x.com/acdlite/status/1797668537349328923

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 v— Reflecting on Mistakes


Next.js 文档版本控制 - nextjs.org/docs

另一个问题是 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>;
  )
}

开发者体验 (DX)

在谈论 Next.js 时,我们不能忽视开发者体验。除了“更快、更高、更强”标准(我们稍后也会讨论)之外,还发布了一些有用的改进。

期待已久的对最新 ESLint 的支持。 Next.js 到目前为止还不支持 ESLint v9。尽管 eslint 本身 (v8) 及其一些子依赖项已被标记为已弃用,但情况仍然如此。这导致了一种不愉快的情况,项目基本上被迫保留已弃用的包。

错误界面略有改进(在 Next.js 中已经清晰方便):

  • 添加了复制堆栈跟踪的按钮;
  • 添加了在编辑器中的特定行打开错误源的功能。

Next.js v— Reflecting on Mistakes


在 next.js 中复制错误堆栈的示例

添加了“静态指示器” - 页面一角的一个元素,显示页面已在静态模式下构建。
总的来说,这是一件小事,但有趣的是他们将其作为新的东西包含在关键更改中。 “预建”页面的指示器大约从版本 8 (2019) 开始就已经存在,本质上,他们只是稍微更新了它并针对 App Router 进行了调整。

Next.js v— Reflecting on Mistakes

还添加了包含调试信息的目录 - .next/diagnostics。它将包含有关构建过程和发生的所有错误的信息。目前尚不清楚这在日常使用中是否有用,但在解决 Vercel devrel 问题时肯定会使用它(是的,它们有时有助于解决问题)。

Next.js v— Reflecting on Mistakes
Next.js 团队对 [关于项目构建速度缓慢的推文] 的回应(https://x.com/darshansrc/status/1797339543571755425)

构建过程的变化

讨论完 DX,值得谈谈构建过程。还有 Turbopack。

涡轮机组

以及该领域最大的新闻。 Turbopack 的开发模式现已完全完成! “Turbopack 100% 的现有测试均通过且没有错误”

现在Turbo团队正在开发生产版本,逐步进行测试和完善(目前完成约96%)

Next.js v— Reflecting on Mistakes
next.js 中的示例变更日志部分

Turbopack 还添加了新功能:

  • 使用 Turbopack 设置构建的内存限制;
  • Tree Shaking(删除未使用的代码)。
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 需求,或者他们将对其进行测试并在下一个版本中呈现。

框架 API 的变化

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 包

还有一些更新:

  • 在 revalidateTag 中,您现在可以一次传递多个标签;
  • 键 images.remotePatterns.search 和 images.localPatterns 已添加到 next/image 的配置中。这些可以更好地控制图像压缩的地址限制。
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 缓存。礼物还是诅咒”一文中主要介绍了。

让我们看看缓存中的所有主要变化:

  • 具体来说,fetch 现在默认使用 no-store 值而不是强制缓存;
  • API 路由现在默认在强制动态模式下工作(之前默认为强制静态,这意味着它们在构建时被编译为静态响应[如果页面上未使用动态 API]);
  • 客户端路由器中的缓存也已被禁用。以前,如果客户端访问路由中的页面 - 它会被缓存在客户端上并保持该状态,直到重新加载页面。现在,每次都会加载当前页面。可以通过 next.config.js 重新配置此功能:
const nextConfig = {
  experimental: {
    turbo: {
      treeShaking: true,
      memoryLimit: 1024 * 1024 * 512 // in bytes / 512MB
    },
  },
}
  • 此外,即使启用了客户端缓存 - 它显然也会在正确的时刻更新。具体来说,如果服务器上启用的页面的缓存过期。
  • 服务器组件现在在开发模式下缓存。这使得开发更新发生得更快。只需重新加载页面即可清除缓存。您还可以通过 next.config.js 完全禁用此功能:
import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  /* config options here */
};

export default nextConfig;
  • 您现在可以管理“Cache-Control”标头。以前,它总是被 Next.js 的内部值严格覆盖。这导致了通过 CDN 进行缓存的工件;
  • next/dynamic 缓存模块并重用它们,而不是每次都重新加载它们;

这就是关于“历史误会”的问题。新的 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)

可能是下一个版本的主要功能。如前所述,PPR 是一种页面构建模式,其中大多数元素在构建时组装并缓存,而单个元素则针对每个请求进行组装。同时,预构建的部分会立即发送到客户端,而其余部分则动态加载。

Next.js v— Reflecting on Mistakes


部分预渲染的工作原理

该功能本身是六个月前在候选版本中作为实验性 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
    },
  },
}

拦截器

拦截器,也称为路由级中间件。它类似于一个成熟的[已经存在的]中间件,但与后者不同:

  • 它可以在 Node.js 运行时运行;
  • 它在服务器上工作(这意味着它可以访问环境和统一缓存);
  • 可以多次添加,嵌套继承(类似于中间件测试版时的工作方式);
  • 它也适用于服务器功能。

此外,当创建拦截器文件时,树中下面的所有页面都会变成动态的。

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 v— Reflecting on Mistakes


在 ChatGPT 中重新混合使用

显然他们在 Next.js 发生重大变化之前就开始了

Next.js v— Reflecting on Mistakes


有关 ChatGPT 从 2024 年 8 月起切换为 Remix 的推文

总的来说,在接下来的 stateofjs 和 stackoverflow 调查中,我们很可能会看到重大的洗牌。

制作人员

代码示例或其基础取自 next.js 文档、提交、PR 和 next.js 核心;

后记

如果您需要一个基于 MD 文件生成文档的工具 - 请查看 robindoc.com,如果您使用 next.js - 您可能会在 nimpl.tech 的解决方案中找到有用的东西。

以上是Next.js v——反思错误的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn