
图1:Next.js 16 版本发布,强调将全栈能力带到前端。
自 next@15 发布并引入 React Server Components (RSC) 特性以来,我便被其深深吸引,并开始在项目中正式采用 Next.js。经过一年多的深度使用,我对它的强大之处有了更深刻的理解。
起初,我认为只有 SEO 优先的项目才需要考虑 Next.js。但现在,我的观念已经彻底转变,将其定位为 全场景首选框架。这种心态的巨大变化,源于对其核心机制——特别是部分水合——的深入理解。
next@16 发布后,伴随 turbopack 的日益成熟,开发环境的响应速度已经达到了不输 Vite 的程度,这进一步印证了我的判断。
为什么是全场景首选?
提出“全场景首选”的观点可能显得非常激进。这里我想强调的是,即便是常规的后台管理系统,使用 Next.js 也比传统的 Vite + React/Vue 方案具备更显著的优势。
在开发 usehook.cn 的过程中,我的项目经历了一次重大重构。最初版本我选择了 Vite + React,后来才重构为现在的 Next.js。
重构的原因主要有两个。首先,用户在初始访问时,页面需要加载的包体积过大,导致首屏加载速度不稳定,部分用户反馈初始访问有时会非常慢。
为了解决这个问题,我尝试了多种方法,最主要的两点是:
- 将静态资源部署到 CDN 上。
- 通过代码分割实现页面的按需加载。
但折腾许久后,我发现效果有限。一方面,开发中已有意识地控制包体积,优化空间不大;另一方面,项目内置了许多渲染工具(如 Markdown 渲染、代码块渲染等),几乎是每个页面都必需的,尤其是代码块和数学公式渲染相关的包,体积相当庞大。
另一个问题是,过大的包体积上传至 CDN 后,流量消耗也很大,时常需要补充流量包。
于是,我萌生了基于 Next.js 重构整个项目的想法。尽管当时项目已非常庞大,重构成本很高。但我确信,Next.js 的特性能够从根本上解决包体积过大的问题。
事实证明了这一点:重构前,首屏加载的 JS 包体积在 gzip 压缩后仍有 2MB 多;重构后,这一数字骤降至 100KB 左右,提升幅度极为夸张。
+ First Load JS shared by all 99.2 kB
├ chunks/215-319cb6c4fa92d97f.js 44.6 kB
├ chunks/4bd1b696-9a8bfc82401e0b67.js 52.6 kB
└ other shared chunks (total) 1.95 kB
这就是 RSC + 部分水合 的威力。虽然整个项目的所有代码都是用 React 编写的,但 Next.js 可以在构建阶段,提前将非交互部分的渲染逻辑处理成静态 HTML。然后通过部分水合,在页面运行时,仅处理交互部分的逻辑。
这意味着,网页在运行时只需执行剩下的一小部分动态渲染逻辑,从而实现了极致的性能体验。
这里特指 App Router,而非 Pages Router。
与 Svelte 的 Signal 相比,这是一种不同思路的 细粒度更新。只要你的项目中存在静态渲染的部分,Next.js 就能展现出比 Svelte 更强大的优势。
什么是部分水合?
早年使用 JSP/PHP + jQuery 开发的项目,在支持 SEO 的同时,还能做到极致的性能体验。项目在服务端处理好 DOM 结构后,在客户端仅需通过 jQuery 获取对应 DOM 并实现交互逻辑即可。
让 DOM 具备交互逻辑的这个过程就可以理解为“水合”。
但这种模式有一个致命缺陷:开发体验不佳。因此,随着现代前端框架和工具链的发展,该模式逐渐被淘汰。然而,我们不得不承认,由于没有“水合”开销,这类项目在生产环境上的性能表现,远优于同构项目。
传统的同构项目需要进行全量水合,这导致 TTI(首次可交互时间) 指标表现较差。水合的目的与 jQuery 类似,都是为了赋予 DOM 交互能力。但由于整个应用完全使用 React/Vue 开发,我们不得不进行全量水合,重新动态渲染整个页面。
Next.js 的部分水合正是为了解决这个问题。如下代码所示,尽管整个项目都用 React 编写,但 Next.js 可以将静态部分在构建 (build) 时处理为静态 DOM 结构,只在页面运行时对剩余的动态部分进行水合。这是一种值得深入了解的前端工程化实践。
import { Suspense } from 'react'
import InteractiveChart from './InteractiveChart'
import StaticContent from './StaticContent'
export default function Page() {
return (
<div>
{/* 完全静态,在 build 时渲染,无需水合 */}
<StaticContent />
<Suspense fallback={<Loading />}>
{/* 只有这部分需要水合 */}
<InteractiveChart />
</Suspense>
</div>
)
}
这种细粒度控制使得 Next.js 能够在服务端渲染出完整的 HTML,然后在客户端仅对必要的组件进行“激活”,大大减轻了客户端的 JavaScript 负担。
Remix 中也提出了类似的概念:Remix Islands(岛屿架构)。Remix 认为,每一个需要交互的区域都是一个独立的“岛屿”,应用只需对这些“岛屿”部分进行水合。
与 Svelte 的对比
谈到性能,我们通常认为在客户端渲染方案中,Svelte 已做到了极致。它利用预编译,在构建时进行依赖收集和数据绑定,实现静态提升,并将状态变化转化为直接操作 DOM 的高效指令,从而绕过了虚拟 DOM。
Svelte 这种方式,在运行时的框架开销非常小。
<!-- Svelte 的响应式是编译时确定的 -->
<script>
let count = 0;
function increment() {
count += 1; // 编译为直接操作 DOM 的代码
}
</script>
<button on:click={increment}>
点击次数: {count}
</button>
因此,Svelte 非常适合开发注重动效的官网首页、活动页或商品介绍页等项目(例如最新的苹果官网就基于 Svelte 开发)。
Svelte 的逻辑是:既然虚拟 DOM 有开销,我就把更新做得足够细,实现精准的“点对点”更新。
Next.js 的逻辑则是:既然 JavaScript 的下载和执行是主要瓶颈,那我就干脆不向客户端发送多余的 JS。
在 Svelte 中,即使渲染高效,你仍需将所有处理交互的逻辑下载到浏览器。而 Next.js 结合 RSC 后,可以将大量静态内容提前处理好,只有真正需要交互的 孤岛(Islands) 才会被发送并进行 水合。这种方式不仅减少了 JS 包体积,也大幅减少了需要维护的虚拟 DOM 数量,从而显著降低了虚拟 DOM 本身的开销。
仅从 客户端开发 的角度,我做了一个对比图:

图2:Next.js SSG/CSR 与传统 CSR 在构建、性能、SEO等多方面的对比。
显然,在 Turbopack 的加持下,即使我们的项目完全没有静态渲染部分,也能获得接近 Vite 的开发体验。
当然,如果你的项目几乎没有静态内容,全部需要动态渲染(例如重交互的编辑器、在线 Excel),那么 Next.js 的优势就不那么明显了。
Turbopack 现状如何?
根据我的使用体验,Turbopack 在编译速度上确实非常快。即使项目庞大,也能获得不输 Vite 的开发体验。
我的项目 usehook.cn 拥有 700 多个页面,每次更新代码后的编译耗时大约在 300ms 多一点。

图3:项目使用 Turbopack 的编译耗时记录,多次编译稳定在 300ms 左右。
在第三方库的兼容性上,由于我的项目使用了较多小众的三方库,而它们在最近一年内都陆续获得了兼容。
因此,我可以得出结论:Turbopack 在兼容性方面的处理已经非常成熟。
Next.js 的其他优势
本文并未花大量篇幅介绍 Next.js 在服务端的表现,而是更多地将重心放在与传统 SPA 方案的对比上,因为大家可能对后者更熟悉。实际上,Next.js 在服务端渲染方面的表现更为优秀。
例如:
- 默认支持的
Link 组件预渲染(预取)。
- 能够更快获得交互响应的流式渲染(Streaming)。
- 对 SEO 友好。
- 完整且极简的文件路由系统。
- 强大且活跃的生态系统。
- 许多云部署平台(如国内较新的 EdgeOne Pages)都优先提供了对 Next.js 的特殊优化支持。
- 服务端的动静混合渲染模式(PPR, Partial Prerendering)。
next@16 中更支持了 组件级别的细粒度增量更新。
除此之外,Next.js 还可以作为 一个全栈框架 或 纯服务端框架,来应对大多数中小型项目。它可以说是开发体验最好的全栈框架之一,提供了前后端一致的开发体验和数据类型。
总结
Next.js 的发展理念体现了一种 混合架构 思维。它正视浏览器的局限性,并利用 预渲染 和 服务端算力 来弥补。这一年多的使用体验告诉我,Next.js 的强大在于它为开发者提供了一把精准的尺子,让你能够在性能与开发效率之间,找到那个完美的平衡点。
目前在国内,能够充分理解 Next.js 的 RSC 与部分水合之强大的人和团队还不多,主要在一些大型互联网公司中较受欢迎。但面向海外的团队,基本上都已拥抱了 Next.js。
在我看来,RSC + 部分水合 是未来非常明确的发展趋势。即使在 Nuxt (Vue) 中,也开始引入 Server Components 的概念(尽管目前还是实验性功能)。
// nuxt.config.ts
export default defineNuxtConfig({
experimental: {
componentIslands: true
}
})
而在 next@16 中,经过两个大版本的迭代,关于 RSC + 部分水合 的构想已基本成熟并落地。对于希望深入探索现代 Web 开发前沿的开发者,可以在 云栈社区 找到更多相关的深度讨论和技术资源。