𝗛𝗼𝘄 𝗪𝗲 𝗖𝘂𝘁 𝗦𝗹𝗼𝘄 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗲𝘀 𝗯𝘆 𝟴𝟬%

Subito is a top marketplace in Italy. We handle thousands of requests every minute. Our ad detail page is vital for SEO and revenue.

We moved this page from Next.js Pages Router to App Router. We did not stop product work to do this. We moved in small steps.

Here is how we did it.

𝗧𝗵𝗲 𝗔𝗽𝗽𝗿𝗼𝗮𝗰𝗵

We used an incremental strategy. We added the App Router tree alongside the old Pages Router. This let us ship new features while we migrated.

We used Server Components to own data fetching. This removed the need to pass data through many layers. We also created a Data Access Layer. This made sure we only fetch data once per request.

We used Suspense and the use() hook to enable HTML streaming. This shows a skeleton screen while data loads. The user sees the page faster.

𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲𝘀

Problem 1: HTTP 410 Gone Search engines need a 410 status when a page is permanently removed. The App Router does not have a built-in way to send this. We solved this using our Express server. The server intercepts the response and changes the status code.

Problem 2: HTML Streaming We found that our loading skeletons did not appear. The page stayed blank for seconds.

We discovered that Nginx and Akamai were buffering our responses. If the CDN buffers the HTML, streaming fails. We had to turn off buffering in Nginx and apply custom settings in Akamai. Once we fixed this, content streamed to the user perfectly.

𝗧𝗵𝗲 𝗥𝗼𝗹𝗹𝗼𝘂𝘁

We rolled out in two phases to protect our SEO.

Phase 1: We moved traffic to the App Router but kept streaming off. We did this one category at a time.

Phase 2: We enabled HTML streaming. We tested this on small categories first. Our SEO team monitored rankings for two weeks before we moved to the next category.

𝗧𝗵𝗲 𝗥𝗲𝘀𝘂𝗹𝘁𝘀

The results were huge. Before the migration, up to 40% of our responses were slow. After the migration, slow responses dropped by 80%.

Most pages now load in under 500ms.

𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀

我们如何通过迁移到 Next.js App Router 将慢响应减少了 80%

在我们构建高性能 Web 应用的过程中,性能始终是我们关注的核心。最近,我们将核心产品从 Next.js 的 Pages Router 迁移到了 App Router。这次迁移不仅是一次架构升级,更是一次性能飞跃——我们将慢响应(slow responses)减少了 80%。

问题所在:Pages Router 的瓶颈

在 Pages Router 中,我们面临的主要挑战是客户端 JavaScript 包(bundle)的大小。由于几乎所有的组件都是客户端组件,我们需要将大量的逻辑、库和状态管理代码发送到用户的浏览器中。

这导致了几个关键问题:

  1. 巨大的 JS Bundle:用户必须下载大量代码才能看到页面。
  2. 水合(Hydration)延迟:浏览器需要解析并执行这些 JS,导致页面虽然看起来加载好了,但无法进行交互(导致 FID 和 TBT 指标升高)。
  3. 数据获取的“瀑布流”问题:虽然 getServerSideProps 很有用,但在复杂的嵌套组件中,数据获取往往会导致请求串行,从而增加了整体等待时间。

解决方案:拥抱 App Router

App Router 的引入带来了 React Server Components (RSC) 的概念,这彻底改变了我们的开发模式。

1. React Server Components (RSC)

通过使用 RSC,我们可以将大部分逻辑留在服务器端。这意味着:

2. 改进的数据获取与缓存

在 App Router 中,数据获取变得更加直观。我们可以直接在异步 Server Components 中使用 await fetch()

// 在 Server Component 中直接获取数据
async function Page() {
  const res = await fetch('https://api.example.com/data');
  const data = await res.json();

  return <main>{/* 渲染数据 */}</main>;
}

Next.js 对 fetch 进行了扩展,提供了内置的缓存机制。这使得我们可以非常轻松地实现数据缓存和重新验证(revalidation),而无需引入复杂的外部状态管理库。

3. 流式传输(Streaming)与 Suspense

以前,如果一个页面有多个数据请求,我们必须等待所有请求完成后才能向用户发送页面。现在,我们可以利用 Streaming 和 Suspense

通过在 loading.js 或使用 <Suspense> 边界,我们可以先向用户展示页面的骨架(skeleton),然后随着数据加载完成,逐步“流式”地填充内容。这极大地提升了感知性能(Perceived Performance)

迁移过程中的挑战

迁移并不是一蹴而就的,我们也遇到了一些挑战:

结论

通过迁移到 App Router,我们不仅显著减少了慢响应,还大幅提升了开发体验。我们的 Core Web Vitals 指标得到了显著改善,用户体验也变得更加流畅。

如果你还在犹豫是否要进行迁移,我们的建议是:尽早开始,从小的组件开始,逐步过渡。