返回 文章 学习 CMS 文章

JavaScript 框架的 AI 成本基准测试:谁更省钱、更快、更轻?

用 AI 代理构建同一应用,量化比较不同 JavaScript 框架的 AI 开发成本与产出质量。

JavaScript框架AI代理基准测试开发成本
成长分 / 100 68 综合收获、行动、留存与影响

JavaScript 框架的 AI 成本基准测试:谁更省钱、更快、更轻?
为什么值得读了解在 AI 代理辅助开发时代,不同 JavaScript 框架的实际成本差异,而非仅凭感觉选择。

获得基于基准测试的框架性能数据(如 JavaScript 字节数、Lighthouse 分数),辅助技术选型。

关键洞察
  1. 构建成本最低的框架是 Hono+htmx($2.67),最高的是 Angular($4.97),但各框架成本区间存在重叠,需考虑方差。
  2. SvelteKit、Gracile+Lit 和 Angular 成本较高,部分原因是代理需要额外阅读迁移指南或框架源码。
  3. Lighthouse 性能、可访问性和 CLS 分数几乎饱和,框架间差异不大,但 JavaScript 字节数差异显著(Astro 0 KiB 到 Next.js 142 KiB)。
转成行动

深入阅读

正文与原文对照

原文保真覆盖:全文原文字符:25214

我对 Web 开发社区的一大不满是,我们做出的许多决定都是基于感觉的。框架“快如闪电”,工具会“超级加速”你的开发,正确的抽象会让开发者和用户都受益(DX 和 UX 一举两得!)。所有这些不喘气的吹嘘通常都没有任何证据。Alex Russell 称之为“前端的失落十年”,Baldur Bjarnason 称编程为流行文化,而我试图在我的博客中用事实和基准测试来对抗这一趋势(至少在我最好的时候是这样)。

很长一段时间里,我们社区对证据的过敏似乎是由对更好 DX 的渴望驱动的。换句话说,开发者就是喜欢在 React 中敲 JSX 的感觉,而推广 React 或相关工具(“虚拟 DOM 很快!”)的论点在很大程度上是为了证明那些最初直觉的事后合理化。(Jonathan Haidt可能会同意这一评估。)

但在智能体时代,当开发者不再手写代码、因而受 DX 的约束更少时,我仍然看到感觉主导一切(而且不只是“氛围编程”意义上的)。前端被重写,是因为某个框架“对智能体更好”。(有人想过问问智能体吗?)结果代码“更快”,智能体“犯更少的错误”,等等。再一次,这些说法往往没有证据。每当我读到这类叙述时,我都会想:“基准测试在哪里?”

好吧,我很好奇,所以我写了一个基准测试。这个基准测试的结构相当直接:

  • 使用PokéAPI设计一个小巧但不简单的 Pokémon 应用(关注我的工作的人不会感到意外)
  • 指示智能体用特定的 JavaScript 框架/元框架(例如 Next.js、Nuxt、SvelteKit 等)构建应用
  • 用规范一致性测试套件测试输出(以避免智能体作弊)
  • 从开发时间、消耗的 token 数、代码行数,以及Lighthouse中的性能和可访问性分数来评估结果

这个应用相当简单:你有一个 Pokémon 列表,包含它们的属性、招式以及来自各种游戏的数据。你可以搜索、筛选等:

一个 Pokémon Web 应用的截图,列出了各种怪物及其属性等。

我应该先说明一些注意事项:这不是一个完美的实验。这个应用只代表一个正模标本——它是一个相对以内容为主的网站,交互性很少,更接近 Wikipedia 而不是 Figma、GMail 等。话虽如此,我总得选择某个应用来构建,而这个应用至少在高层次上容易理解,并且相对容易编写规范和测试。

为了尽量公平,我让每个框架/元框架使用该工具的官方 MCP 或 skills。我想避免“这个框架在训练数据中代表性不足,这就是我们构建 MCP 的原因,我们期望人们使用它”之类的指责。我也没有过度指定要使用的确切架构(例如 SSR 还是 CSR),也没有指定应用应尽可能高性能。我只是把规范交给 Opus 5.5,并设置高努力,告诉它使用给定框架的最新版本。每个智能体都在沙箱中运行,并且不知道它将在 Lighthouse 中接受性能和可访问性测试,尽管它获得了规范一致性测试套件。

注意,我也没有强制任何 CSS 方法论,只是避免使用 Tailwind、Bootstrap 或任何其他组件框架,并基于一组规范 token 进行设计以强制某种视觉一致性。我不想让这个测试完全围绕 CSS,而是围绕 JS 框架、CSR 与 SSR、SPA 与 MPA 等。生成的应用基于可访问性树而不是原始 DOM 进行一致性测试套件测试,以避免强制任何特定的 HTML 结构——一个框架使用了依赖 shadow DOM 的 Web Components,所以这是必需的。

我从这个实验中学到的一件事是,我所测量的一切都非常随机。LLM 是随机词生成器,所以有时你会掷出低点数,智能体会跑偏到某个奇怪的切线,浪费大量 token,而这并非框架或其工具的过错。Lighthouse 本身也可能给出不一致的结果:最大内容绘制(LCP)可能决定一张图像是“最大”元素,然后在下次运行时选择另一张。很难有一个完全公平的实验,但运行多次迭代确实有帮助,我也尽量对差异保持诚实。

清完嗓子,让我们进入结果。

结果

我将从多个维度来分解:构建成本、质量和可维护性。对于每个框架/元框架,我取 5 次运行的中位数:换句话说,我在同一框架中构建了同一个应用 5 次。(是的,这就是如今用编码智能体可以做的疯狂事情。)

例外是 Angular,它两次未能创建可测量的应用,所以对于某些指标我改用了 3 次迭代。(下面会解释。)

成本

每次运行的成本,以美元计

框架 成本($)
Hono+htmx $2.67 (2.23–3.19)
Astro $2.76 (2.16–3.63)
Nuxt $2.82 (2.39–4.25)
Vanilla $2.98 (2.24–3.37)
Next.js $3.14 (2.58–4.13)
Qwik $3.27 (2.35–3.80)
TanStack Start $3.54 (3.11–3.96)
SolidStart $3.79 (2.84–4.81)
React Router $3.81 (2.82–3.97)
SvelteKit $4.28 (3.59–4.65)
Gracile+Lit $4.65 (3.92–5.07)
Angular $4.97 (3.19–6.82)
02468

5 次运行的中位数。

请注意,这直接引用了 Claude Code 的 API 价格,并不实际代表我花了多少钱。我使用的是 Max 计划,所以这只是我每月 100 美元总支出的一部分。

还要注意方差:React Router 的中位数比 Hono+htmx 差约 1 美元,但 React Router 最便宜的版本(2.82 美元)仍然比 Hono+htmx 最贵的版本(3.19 美元)便宜。然而,一些可靠的模式确实出现了。

最明显的是,SvelteKit、Gracile+Lit 和 Angular 的构建成本高于其他框架。对于 SvelteKit,这可能是因为智能体在每次运行中都会阅读 SvelteKit v3 迁移指南,很可能是因为它太新,不在 Opus 5.5 的训练数据中。Gracile 同样如此,智能体对该框架不太了解,要么克隆了 Gracile 仓库,要么从 node_modules 读取其编译后的源码。对于 Angular,这似乎是代码总规模的函数(见下文)。

我还应该提到,并非每个智能体都使用了 MCP/skill/Claude Code 插件,也并非每个框架都有这样的插件:

点击查看 AI 工具使用情况

框架 已安装 智能体是否使用?
Angular Angular MCP 和 Angular agent skills 5 次运行中 3 次使用 MCP,5 次运行中 4 次使用 skill 工具,5 次运行中 2 次使用 skill 文件
Astro Astro MCP server 5 次运行中 2 次使用 MCP
Gracile+Lit 不适用 不适用
Hono+htmx Hono skills 5 次运行中 5 次使用 skill 工具
Next.js next-devtools-mcp 和 next-dev-loop skill 5 次运行中 1 次使用 skill 文件,5 次运行中 2 次使用 AGENTS.md
Nuxt Nuxt MCP 不适用
Qwik 不适用 不适用
React Router React Router skill 5 次运行中 5 次使用 skill 工具,5 次运行中 5 次使用 skill 文件
SolidStart 不适用 不适用
SvelteKit Svelte Claude Code 插件 5 次运行中 5 次使用 MCP
TanStack Start 不适用 5 次运行中 2 次使用 skill 文件
Vanilla 不适用 不适用

例如,TanStack Start 的智能体仅在 5 次运行中的 2 次发现了其 skill 文件(它们随项目的 node_modules 一起提供)。对于 Nuxt,智能体从未使用过 MCP。对于 Next.js,智能体仅在 5 次运行中的 1 次阅读了 skill 文件,在 5 次运行中的 2 次阅读了 AGENTS.md。结果范围很广,这又指向了 LLM 的随机性。不过,我仍然认为这是一个有效的实验,因为我怀疑很多 vibe-coder 并不会用全大写字母对智能体大喊要求使用 MCP(而且很多人可能完全跳过它)。

另外,如果你想知道我是如何想到 Hono+htmx 的:基本上,我想以某种方式代表 htmx,而 Hono 似乎是一个不错的搭配(即作为 Rails/Django 等的 JavaScript 替代品)。至于 Gracile+Lit,我想通过其标准承载框架(Lit)来代表 Web 组件,而我只知道 Gracile 是一个元框架。如果有更好的候选者,那么它们将非常适合后续实验。

对于“Vanilla”,请注意智能体被告知使用“vanilla JavaScript 或 TypeScript 配合 Vite,不使用 UI 框架”。令人惊讶的是,它的表现不如几个框架,这似乎表明拥有某种框架总比没有好(或者至少比原始 Vite 好)。选择 Vite 是因为它支撑了许多框架,并代表了相当标准和无关的 JavaScript 基础设施。

总时间和 token 与成本跟踪得相当紧密:

每次运行的时间

框架 时间(分钟)
Astro 8.2 分钟(6.2–9.7)
Hono+htmx 8.6 分钟(5.9–9.6)
Nuxt 9.0 分钟(8.0–17.6)
Vanilla 10.1 分钟(6.9–18.6)
TanStack Start 10.3 分钟(8.3–13.9)
Qwik 10.7 分钟(7.1–12.9)
SvelteKit 10.8 分钟(8.6–13.8)
Next.js 10.9 分钟(8.3–11.9)
SolidStart 11.2 分钟(8.2–15.9)
Gracile+Lit 12.1 分钟(10.8–12.9)
React Router 12.5 分钟(8.4–13.6)
Angular 17.2 分钟(9.8–23.7)
0510152025

从智能体视角计的挂钟分钟数。5 次运行的中位数。

每次运行的 token 数,单位为百万

框架 Token 数(百万)
Nuxt 3.85 M(3.16–8.18)
Astro 4.13 M(3.03–7.57)
Hono+htmx 4.26 M(3.40–5.61)
Next.js 4.99 M(3.54–8.82)
Vanilla 5.00 M(3.44–6.32)
Qwik 5.64 M(3.41–7.03)
TanStack Start 7.07 M(5.85–7.99)
SolidStart 7.13 M(5.02–10.07)
React Router 7.58 M(4.55–8.18)
SvelteKit 8.53 M(6.79–9.29)
Gracile+Lit 9.04 M(7.36–11.10)
Angular 9.76 M(4.92–14.94)
051015

缓存读取、未缓存输入与输出。5 次运行的中位数。

顺便说一下,这些 token 数是由 Claude Code 报告的。时长只是总的挂钟时间。

质量

当然,因为我认为结果很重要,所以我也用 Lighthouse 测试了这些智能体。作为软件开发者,我认为重要的是我们不仅要低成本地构建东西,还要保证性能和可访问性。

我首先应该说明关于我的基准测试的两点注意事项:

  • 这个 Pokémon 应用很小,并不能代表大型、复杂的真实世界应用。
  • Lighthouse 以及总体上核心网页指标(Core Web Vitals)对 SPA 存在偏见,因此 MPA 框架几乎必然会在总阻塞时间(TBT)、JavaScript 字节数等指标上胜出。我曾考虑加入一些应用内性能指标,但最终放弃了,因为这会给基准测试增加复杂性和变异性,而且这些指标会是我自己发明的,而非行业标准。

为简单起见,我只报告首页的分数。还有其他页面,但它们的得分都相当相似,或者像 LCP 这样的指标波动很大,所以把它们包含进来只会让事情复杂化。

简而言之:性能、可访问性和 CLS(累积布局偏移)的 Lighthouse 分数几乎已经饱和,并且不会因框架而有太大差异:

框架 CLS 性能 可访问性
Angular 0.000 98 100
Astro 0.000 100 100
Gracile+Lit 0.000 100 100
Hono+htmx 0.000 100 100
Next.js 0.000 99 100
Nuxt 0.000 100 100
Qwik 0.000 100 100
React Router 0.000 100 100
SolidStart 0.000 100 100
SvelteKit 0.000 100 100
TanStack Start 0.000 99 100
Vanilla 0.111 97 100

因此,要得到一些更有意思的数字,我们需要看其他指标。最可靠的是发送的 JavaScript 字节数,它很大程度上反映了客户端框架的大小:

传输的 JavaScript 字节数

框架 JS(KiB)
Astro 0 KiB(0–1)
Vanilla 7 KiB(6–7)
Gracile+Lit 8 KiB(1–13)
Hono+htmx 18 KiB(18–18)
SvelteKit 36 KiB(35–36)
SolidStart 40 KiB(38–40)
Qwik 40 KiB(40–41)
Nuxt 84 KiB(83–85)
Angular 93 KiB(81–102)
React Router 115 KiB(115–119)
TanStack Start 118 KiB(112–119)
Next.js 142 KiB(136–143)
050100150

由 Lighthouse 报告。5 个应用的中位数(Angular 为 3 个)。

总阻塞时间(TBT)有意思的地方在于,它并不纯粹是 JavaScript 字节数的函数;有些应用在主线程上花费的时间比其他应用更多。话虽如此,这些数字都相当小:

总阻塞时间(TBT)

框架 TBT(ms)
Astro 0 ms(0–0)
Gracile+Lit 0 ms(0–0)
Hono+htmx 0 ms(0–0)
SvelteKit 0 ms(0–1)
Vanilla 0 ms(0–0)
TanStack Start 1 ms(0–36)
Qwik 3 ms(0–30)
SolidStart 11 ms(0–12)
React Router 17 ms(0–52)
Nuxt 40 ms(14–54)
Next.js 71 ms(66–121)
Angular 103 ms(93–123)
0255075100125

由 Lighthouse 报告,模拟移动端节流。每个应用取 5 次 Lighthouse 运行的中位数,然后再取 5 个应用的中位数(Angular 为 3 个)。

最大内容绘制(LCP)由于前述该指标本身的问题而波动很大。不过正如预期,它总体上会惩罚 SPA 而奖励 MPA:

最大内容绘制(LCP)

框架 LCP(ms)
Astro 810 ms(792–1662)
Gracile+Lit 956 ms(796–980)
Hono+htmx 978 ms(977–1662)
Qwik 979 ms(954–1278)
SvelteKit 1130 ms(1129–1131)
SolidStart 1204 ms(1203–1278)
Vanilla 1667 ms(764–1676)
Nuxt 1727 ms(1427–1844)
React Router 1729 ms(1729–1770)
Angular 1954 ms(1351–1955)
TanStack Start 2028 ms(1805–2104)
Next.js 2090 ms(1028–2187)
05001000150020002500

由 Lighthouse 报告,模拟移动端节流。每个应用取 5 次 Lighthouse 运行的中位数,然后再取 5 个应用的中位数(Angular 为 3 个)。

测试环境:2025 款 Framework 13 笔记本电脑,运行 Ubuntu 24.04,4 倍 CPU 节流,以及“Slow 4G”网络节流。我只运行了 Lighthouse 的移动端测试,没有运行其桌面端测试。

请注意,Next.js 数值的巨大差异可以解释为:一个应用避免了图片懒加载,而另外四个应用没有。Astro 和 Vanilla 也有类似的波动,似乎是由优先级或 LCP 的怪癖造成的。

不过总的来说,这个指标倾向于奖励用 HTML 快速绘制的 MPA,而不是在客户端 JavaScript 运行后才绘制的 SPA(后者可能还需要多次受节流影响的往返来获取 Pokémon 数据),这并不令人意外。忽略波动的话,这里的 LCP 主要是 JavaScript 包大小的函数。(Qwik 在这里是一个显著的例外:严格来说它是一个使用客户端路由的 SPA,但它的得分却处于 MPA 框架之列。)

不过请注意,一些框架在更侧重客户端还是服务器上存在差异,甚至是否使用客户端框架也不尽相同。例如,Gracile 智能体在两次运行中甚至没有使用 Lit。对于“Vanilla”,智能体拥有完全的自由(除了被告知要使用 Vite),但仍然在全部 5 次中都选择构建 SPA。

SSR 与 CSR 也是 Angular 部分问题的来源:在 2 次运行中,智能体构建了一个拒绝非 localhost 的 SSR 应用(尽管说明中明确写道该应用将位于反向代理之后)。我认为这是未遵守规范的有效失败,并决定不重新运行这 2 次失败的迭代。(这只影响代码大小和性能测量;在“成本”部分,我报告了全部 5 次 Angular 迭代。)

可维护性

衡量可维护性的方法有很多(包括圈复杂度之类花哨的东西),但我决定保持简单,报告一个久经考验的指标:代码总行数。

代码行数

框架 代码行数
Hono+htmx 1370 (1264–1489)
Nuxt 1415 (1382–1458)
Astro 1461 (1379–1503)
Vanilla 1492 (1437–1742)
Next.js 1539 (1452–1627)
React Router 1564 (1421–1621)
SvelteKit 1611 (1503–1816)
SolidStart 1630 (1528–1894)
TanStack Start 1697 (1506–1771)
Gracile+Lit 1717 (1412–1748)
Qwik 1744 (1646–1827)
Angular 2009 (2003–2051)
05001000150020002500

非空源文件行数。5 个应用的中位数(Angular 为 3 个)。

对我来说,这是比较有趣的图表之一。从某种意义上说,框架的全部意义就在于减少你需要维护的代码量。用 Rich Harris 令人难忘的话来说:

“框架不是组织代码的工具;它们是组织思维的工具。”

——Rich Harris,“重新思考响应式”

在智能体时代,这一点更加重要,因为代码大小最终会影响 token 数量,包括在未来的编辑中,这意味着它会影响随时间推移维护代码库的实际成本。这并不意味着简洁是唯一重要的价值,但看到 Hono+htmx 能用约 70% 的代码完成与 Angular 大致相同的事情(而且速度还更快),确实很有趣。

结论

你可以用很多方式改进这个基准测试。例如,你可以要求智能体使用 Service Workers 进行离线缓存,或者优化 Pokémon 图片文件,或者使用懒加载、fetchpriority、Speculation Rules API 等。尽管我知道很多这类性能技巧,但我刻意没有引导智能体去使用其中任何一种,因为这不是典型的 vibe-coder 会做的事。

另一方面,只要把所有 HTML 文件预生成为静态资源(Pokémon 数量有限),整个基准测试就可以被作弊。我在指令中明确禁止了这一点,并在测试框架中将其设为显式检查,因为我觉得这不符合基准测试的精神。(我的目标是模拟大量可能是动态的数据,这比纯静态站点更具挑战性。)

你也可以改进我运行基准测试的方式:运行更多迭代、使用不同的编码智能体、尝试不同的努力程度、使用不同的框架或框架的不同版本、尝试使用和不使用 MCP/skills、在 Chromium 之外的更多浏览器中测试、构建不同类型的应用等。我没有做这些事,主要是为了节省时间。不过,如果有人想自己运行这个基准测试或 fork 它,它就在 GitHub 上,所以我鼓励你尽情折腾。我会很乐意在这里报告你的结果(以及你可能发现的任何错误或缺陷)。

我在这里的目标不是写出“我是个 vibe-coder,该选哪个框架?”的终极基准测试。这篇文章的重点是证明,在 AI 编码时代,仍然有可能基于证据而不是感觉来做决定。这个基准测试本身很大程度上是 vibe-coded 的,尽管我确实审查了代码,所以如果有错误,请把它们算在我头上。我也非常乐意看到竞争框架尝试改进我在这里所做的工作。

我也不是想诋毁任何特定框架。在运行基准测试之前,我并不知道哪一个会“赢”,尽管我确实怀疑 MPA 会胜过 SPA(我在整篇文章中都乐于承认这一点)。你当然可以通过把应用做成复杂仪表盘、电子游戏、生产力应用等,来编写一个更偏向 SPA 的基准测试。你也可以选择不同的指标:Lighthouse 和 Core Web Vitals 对 SPA 相当苛刻,所以你可以改为衡量应用内交互性。

我也确信,框架作者们自己可以改进他们的框架或 AI 工具,并在这个基准测试中做得更好。例如,我强烈怀疑当前这批 MCP 和 skills 可能弊大于利。所以,如果这篇文章成为这些框架性能的最终定论,我会非常失望。我也确信,还有一些新兴框架正迫不及待地想在这样的基准测试中取得好成绩。

至少,我希望这篇文章能启发你在这个奇异的 vibe coding 新时代,对 JavaScript 框架的选择进行额外的审视。你真的是基于证据来选择技术栈吗?还是只是沿用你已经熟悉的东西?这完全可以理解,尤其是如果你仍然亲自阅读、审查和调试代码。但如果你已经基本放手不管,那么你对当年像动物一样逐行敲代码时所做的选择,究竟还有什么执念?如果你正在重新评估构建软件的整个方式,也许值得重新评估一下你在 npm install 之后输入的内容?只是说说而已。

就个人而言,除了我相信我们应该努力为用户构建尽可能最好的体验之外,我对上面评估过的框架没有任何执念。我认识并尊重上述许多框架的作者,我知道他们正在为我所倡导的相同价值而不懈努力。我只是希望推动整个社区朝着更好的方向前进,打造更好、更快、更易访问的框架,为下一代 Web 应用提供动力。

附录

测试中使用的框架版本(注意 Qwik 在测试中途发布了一个补丁版本):

框架 版本
Angular @angular/core 22.2.3
Astro astro 7.4.2
Gracile+Lit @gracile/gracile 0.11.0, lit 3.3.3
Hono+htmx hono 4.13.14, htmx.org 2.0.11
Next.js next 16.4.3, react 19.3.1
Nuxt nuxt 4.6.2, vue 3.5.44
Qwik @builder.io/qwik-city 1.20.2(第 1 次迭代),1.20.3(第 2、3、4、5 次迭代),@builder.io/qwik 1.20.2(第 1 次迭代),1.20.3(第 2、3、4、5 次迭代)
React Router react-router 8.5.0, react 19.3.1
SolidStart @solidjs/start 2.1.0, solid-js 1.9.17
SvelteKit @sveltejs/kit 3.1.0, svelte 5.57.2
TanStack Start @tanstack/react-start 1.169.4, react 19.3.1
Vanilla vite 8.3.5

更新:本文早期版本夸大了 Angular 智能体无法构建可运行应用的程度。我已澄清每个指标的迭代次数,并重新措辞本文以避免歧义。

你可以在 fediverse 或 Hacker News 上发表评论。