← 文章 / 编程开发
cloudflare 43分钟前 · 2026-10-01 10:19:09 · 1 阅读

如何用 AI 在一周内重写 Next.js

BLOG-3194 1

*本文于太平洋时间下午 12:35 更新,修正了构建时间基准测试中的一处笔误。

上周,一位工程师和一个人工智能模型从零重写了当下最流行的前端框架。成果就是 vinext(读作 "vee-next"),一个 Next.js 的无缝替代方案。它基于 Vite 构建,一条命令即可部署到 Cloudflare Workers。早期基准测试显示,它构建生产应用的速度最高快 4 倍,客户端产物体积最高缩小 57%。目前已有客户在生产环境中使用它。

整个项目消耗的 token 费用大约是 1,100 美元。

Next.js 的部署难题

Next.js 是最流行的 React 框架,数百万开发者在使用它,支撑着生产环境中相当大一部分网站——这并不奇怪,它的开发体验确实一流。

但在更广泛的 serverless 生态中,Next.js 存在部署难题。它的工具链完全是为自家定制的:Next.js 在 Turbopack 上投入很大,可如果你想把它部署到 Cloudflare、Netlify 或 AWS Lambda,就得把构建产物重新加工成目标平台能实际运行的形态。

如果你在想:“这不就是 OpenNext 干的事吗?”没错。

OpenNext 正是为解决这个问题而生的。包括 Cloudflare 在内的多家厂商都为它投入了大量工程精力。它确实能用,但很快就会碰到各种限制,陷入打地鼠式的补丁循环。

实践证明,以 Next.js 的构建产物为基础再做改造,是一种困难且脆弱的做法。OpenNext 需要逆向解析 Next.js 的构建输出,而版本之间的产物变化难以预料,往往要花大量精力去修复。

Next.js 一直在开发一流的 Adapters API,我们也在此过程中与其保持协作。虽然这项工作仍处于早期阶段,但即便有了 Adapters,你依然是在定制化的 Turbopack 工具链上进行开发。且 Adapters 仅覆盖构建和部署环节。在开发阶段,next dev 只能运行在 Node.js 上,无法接入其他运行时。如果应用使用了平台特定的 API,比如 Durable Objects、KV 或 AI 绑定,开发者无法在开发环境中直接测试相关代码,必须依赖变通方案。

推出 vinext

BLOG-3194 2

如果不去适配 Next.js 的输出,而是直接在 Vite 上重新实现 Next.js 的 API 接口,会怎样?Vite 是 Next.js 之外前端生态系统中最常用的构建工具,支撑着 Astro、SvelteKit、Nuxt 和 Remix 等框架。这是一次彻底的重新实现,而非简单的封装或适配器。说实话,我们原本以为这行不通。但在 2026 年,软件开发成本已经发生了巨变。

我们的进展远超预期。

npm install vinext

只需将脚本中的 next 替换为 vinext,其他配置保持不变。现有的 app/、pages/ 和 next.config.js 均可直接使用。

vinext dev          # 支持 HMR 的开发服务器
vinext build        # 生产环境构建
vinext deploy       # 构建并部署到 Cloudflare Workers

vinext 不是对 Next.js 和 Turbopack 输出的封装,而是 API 接口的另一种实现:路由、服务器渲染、React Server Components、服务端动作、缓存及中间件。所有这些功能均作为插件构建在 Vite 之上。最关键的是,得益于 Vite Environment API,Vite 的输出可运行在任意平台上。

数据表现

早期的 基准测试结果颇具潜力。我们使用一个包含 33 个路由的共享 App Router 应用程序,将 vinext 与 Next.js 16 进行了对比。

两个框架执行的任务其实一样:编译、打包以及准备服务器渲染路由。我们在 Next.js 构建过程中关闭了 TypeScript 类型检查和 ESLint(因为 Vite 在构建时不运行这些工具),并使用了 force-dynamic,防止 Next.js 花费额外时间去预渲染静态路由,以免不公平地拉低其性能数据。我们的目标只是衡量打包器和编译速度,不涉及其他因素。基准测试在 GitHub CI 上针对合并到 main 分支的每次提交自动运行。

生产环境构建时间:

框架 平均值 相比 Next.js
Next.js 16.1.6 (Turbopack) 7.38s 基准线
vinext (Vite 7 / Rollup) 4.64s 快 1.6 倍
vinext (Vite 8 / Rolldown) 1.67s 快 4.4 倍

客户端包体积(Gzip 压缩后):

框架 Gzip 后大小 相比 Next.js
Next.js 16.1.6 168.9 KB 基准线
vinext (Rollup) 74.0 KB 小 56%
vinext (Rolldown) 72.9 KB 小 57%

这些基准测试衡量的是编译和打包速度,而非生产环境下的服务性能。测试用例仅包含一个拥有 33 个路由的应用程序,并不能代表所有生产级应用的完整情况。随着三个项目的持续开发,这些数据预计会发生变化。完整方法论文档及历史结果已公开。请将这些数据视为方向性参考,而非定论。

不过,方向令人鼓舞。Vite 的架构,尤其是 Rolldown(即将随 Vite 8 推出的基于 Rust 的打包器),在构建性能方面具有结构性优势,这一点在以上结果中体现得非常明显。

部署到 Cloudflare Workers

vinext 将 Cloudflare Workers 作为首选部署目标进行构建。一条命令即可将源代码转化为正在运行的 Worker:

vinext deploy

它处理所有事务:构建应用程序、自动生成 Worker 配置并执行部署。App Router 和 Pages Router 均能在 Workers 上运行,支持完整的客户端水合、交互式组件、客户端导航以及 React 状态管理。

在生产级缓存方面,vinext 内置了 Cloudflare KV 缓存处理器,开箱即支持 ISR(增量静态再生成):
import { KVCacheHandler } from "vinext/cloudflare";
import { setCacheHandler } from "next/cache";

setCacheHandler(new KVCacheHandler(env.MY_KV_NAMESPACE));

KV 对大多数应用来说是不错的默认选择,但缓存层设计上是可插拔的。通过 setCacheHandler 调用,你可以接入任何合适的后端。如果应用有较大的缓存载荷或不同的访问模式,R2 可能更合适。我们还在改进 Cache API,目标是让它以更少的配置提供强大的缓存能力。核心理念就是灵活:为你的应用选择合适的缓存策略。

目前已在运行的示例:

我们还有 一个在线示例,展示了在 Next.js 应用中运行 Cloudflare Agents,而且不需要 getPlatformProxy 这类变通方案,因为从开发到部署,整个应用都跑在 workerd 里。这意味着可以毫无妥协地使用 Durable Objects、AI bindings 以及其他所有 Cloudflare 专属服务。欢迎查看。

框架是团队协作的成果

当前的部署目标是 Cloudflare Workers,但这只是一小部分。vinext 大约 95% 的代码是纯 Vite。路由、模块 shim、SSR 流水线、RSC 集成——没有一样是 Cloudflare 专属的。

Cloudflare 正积极寻求与其他托管服务商合作,推广这套工具链以满足其客户需求(迁移成本极低——我们在 Vercel 上不到 30 分钟就跑通了概念验证!)。这是一个开源项目,为了长期的成功,我们认为必须与生态系统中的合作伙伴携手,确保持续投入。我们欢迎来自其他平台的 Pull Request(PR)。如果你对添加新的部署目标感兴趣,请提一个 issue 或联系我们。

状态:实验性

我们需要明确:vinext 仍处于实验阶段。它诞生不到一周,尚未经历大规模真实流量的考验。如果你正考虑将其用于生产环境,请务必谨慎评估。

不过,我们的测试套件非常详尽:包含 1,700 多个 Vitest 测试用例和 380 个 Playwright 端到端测试,其中包括直接移植自 Next.js 测试套件和 OpenNext Cloudflare 合规套件的测试。我们已通过 Next.js App Router Playground 进行验证。对 Next.js 16 API 表面的覆盖率达到 94%。

来自早期真实用户的反馈令人鼓舞。我们正与 National Design Studio 合作,这是一个致力于现代化政府界面的团队。我们在其一个 Beta 站点 CIO.gov 上使用了 vinext。他们已在生产环境中运行 vinext,在构建时间和包体积方面获得了显著优化。

README 诚实地列出了不支持且未来也不会支持的功能,以及已知限制。我们希望坦诚相待,而非过度承诺。

关于预渲染

vinext 开箱即支持增量静态再生(Incremental Static Regeneration, ISR)。任何页面在首次请求后会被缓存并在后台重新验证,行为与 Next.js 一致。这部分功能目前完全可用。

vinext 尚不支持构建时的静态预渲染。在 Next.js 中,不包含动态数据的页面会在 next build 期间渲染,并作为静态 HTML 提供。如果你使用了动态路由,通常会调用 generateStaticParams() 来枚举需要预先构建的页面。vinext 暂时还不具备这一功能。

这是发布时的有意设计取舍。它 已列入路线图,但如果你的站点完全由预构建的 HTML 和静态内容组成,今天从 vinext 中获益可能有限。不过话说回来,如果一位工程师花 1,100 美元的 token 费用就能重构 Next.js,那你大概花 10 美元就能迁移到专为静态内容设计的 Vite 框架(比如 Astro,它 也支持部署到 Cloudflare Workers)。

但对于非纯静态站点,我们认为可以做得比在构建时预渲染所有内容更好。

引入流量感知预渲染

Next.js 在构建期间会预渲染 generateStaticParams() 中列出的每一页。拥有 10,000 个产品页的站点,意味着构建时需要渲染 10,000 次,尽管其中 99% 的页面可能永远不会收到任何请求。构建时间与页面数量呈线性增长,这也是大型 Next.js 站点构建时间长达 30 分钟的原因。

因此,我们构建了流量感知预渲染(TPR)。目前它仍处于实验阶段,计划在获得更多实际测试数据后将其设为默认行为。

思路很简单。Cloudflare 本身就是你站点的反向代理,我们掌握着你的流量数据,知道哪些页面真的被访问过。于是,vinext 不再选择全部预渲染或不预渲染,而是在部署时查询 Cloudflare 的 zone 分析,只预渲染那些真正重要的页面。

vinext deploy --experimental-tpr

  Building...
  Build complete (4.2s)

  TPR (experimental): Analyzing traffic for my-store.com (last 24h)
  TPR: 12,847 unique paths — 184 pages cover 90% of traffic
  TPR: Pre-rendering 184 pages...
  TPR: Pre-rendered 184 pages in 8.3s → KV cache

  Deploying to Cloudflare Workers...

对于一个拥有 100,000 个产品页的站点,幂律分布意味着 90% 的流量通常集中在 50 到 200 个页面上。这些页面在几秒内即可完成预渲染。其余页面回退到按需 SSR,并在首次请求后通过 ISR 进行缓存。每次新部署都会根据当前的流量模式刷新预渲染集合。那些突然爆火的页面会被自动纳入。这一切都不需要 generateStaticParams(),也不会将构建过程与生产数据库耦合在一起。

用 AI 发起挑战 Next.js

这样的项目通常需要一个工程师团队花上几个月甚至几年。多家公司的好几个团队都尝试过,工程量实在太大——Cloudflare 自己也试过一次!双路由器、33+ 个模块 shim、服务端渲染管线、RSC 流式传输、文件系统路由、中间件、缓存、静态导出。至今没人成功,不是没有原因的。 这次我们不到一周就搞定了。一位工程师(严格来说是工程经理)指挥 AI 完成。 第一个 commit 提交于 2 月 13 日。当天晚上结束前,Pages Router 和 App Router 都已实现了基础 SSR,中间件、server actions 和流式传输也能跑通。第二天下午,App Router Playground 已能渲染 11 个路由中的 10 个。到第三天,`vinext deploy` 就能把应用部署到 Cloudflare Workers 并完成完整的客户端 hydration。接下来的一周剩余时间都在打磨:修复边界情况、扩充测试套件、把 API 覆盖率提升到 94%。 和之前的尝试相比,变的是什么?AI 变强了,强太多了。

为什么这个问题天生适合 AI

并不是所有项目都能这样做成,这个项目可以,是因为几个条件恰好同时具备。

Next.js 规范清晰。它有详尽的文档、庞大的用户群,以及多年积累的 Stack Overflow 问答和教程,整个 API 都在训练数据里。让 Claude 实现 `getServerSideProps` 或解释 `useRouter` 的工作原理时,它不会胡编乱造——它真的懂 Next 的运作方式。

Next.js 有完善的测试套件。Next.js 仓库包含数千个 E2E 测试,覆盖了每个功能和边界情况。我们直接从他们的套件移植测试(代码中可以看到出处标注)。这给了我们一套可以机械化验证的规格说明。

Vite 是绝佳的基础。Vite 已经解决了前端工具链中最难的部分:快速 HMR、原生 ESM、干净的插件 API、生产环境打包。我们不用自己造打包器,只需要教会它 Next.js 的“语言”。@vitejs/plugin-rsc 虽然还很早期,但让我们无需从零实现 RSC,就获得了 React Server Components 的支持。

模型跟上了。我们认为,几个月前还做不到这一点。早期的模型无法在如此庞大的代码库中保持连贯性。新模型能够将完整架构纳入上下文,推理模块之间的交互方式,并且经常能生成正确的代码以维持开发节奏。有时,我看到它深入研究 Next、Vite 和 React 的内部机制来排查 bug。最新模型表现出色,且似乎仍在不断进步。

这些条件必须同时满足。目标 API 文档详尽、测试套件全面、底层构建工具扎实,以及一个真正能应对复杂性的模型。拿走其中任何一项,效果都会大打折扣。

我们的实际构建过程

vinext 中几乎每一行代码都由 AI 编写。但更重要的是:每一行代码都通过了与人工编写代码相同的质量关卡。项目拥有 1,700 多项 Vitest 测试、380 项 Playwright 端到端测试、通过 tsgo 进行的完整 TypeScript 类型检查,以及通过 oxlint 进行的代码风格检查。持续集成会在每个拉取请求上运行所有检查。建立一套良好的护栏对于让 AI 在代码库中高效工作至关重要。

整个过程从规划开始。我花了几个小时在 OpenCode 中与 Claude 来回推敲以定义架构:构建什么、按什么顺序、使用哪些抽象。这份计划成为了北极星。在此基础上,工作流程很直接:

  1. 定义任务(例如“实现包含 usePathname、useSearchParams、useRouter 的 next/navigation 垫片”)。
  2. 让 AI 编写实现和测试。
  3. 运行测试套件。
  4. 如果测试通过,合并代码;如果不通过,将错误输出反馈给 AI,让它迭代修正。
  5. 重复上述步骤。

我们也为代码审查接入了 AI 代理。当 PR 打开时,一个代理会进行审查。当审查评论返回时,另一个代理会处理这些意见。反馈循环基本上实现了自动化。

AI 并非每次都能做到完美。有些 PR 完全搞错了,AI 有时会自信地实现一个看起来正确但与 Next.js 实际行为不符的方案。我不得不频繁地纠正方向。架构决策、优先级排序、判断 AI 是否走入死胡同——这些全靠我。当你给 AI 清晰的方向、良好的上下文和护栏,它确实能产出很多工作。但方向盘始终掌握在人手里。

对于浏览器层面的测试,我使用了 agent-browser 来验证实际渲染输出、客户端导航和 hydration 行为。单元测试往往会遗漏很多细微的浏览器问题,而它能捕捉到这些。

整个项目过程中,我们在 OpenCode 上运行了超过 800 个会话。总成本大约是 $1,100 的 Claude API 代币。

这对软件意味着什么?

为什么软件技术栈要有这么多层?这个项目迫使我深入思考这个问题,以及 AI 如何影响答案。

软件中大多数抽象层之所以存在,是因为人类需要辅助。我们无法在脑中容纳整个系统,所以构建层次来帮我们管理复杂度。每一层都让下一位开发者的工作更轻松。久而久之,就形成了框架套框架、包装库、成千上万行胶水代码的局面。

AI 没有这种限制。它能将整个系统放在上下文中,直接编写代码。它不需要中间框架来保持有序。它只需要一个规范和一个基础来构建即可。

原始来源: cloudflare

评论 (0)