vatt'ghern jaskier's ballads
本文 1 個互動圖表在手機上以重點摘要呈現,互動版請以桌面瀏覽器開啟。

同一份 spec、同一個 Pokémon 圖鑑 app,交給 Opus 5.5 用十二種前端組合各寫五次:費用中位數最低 US$2.67,最高 US$4.97,而最貴的 Angular 還有兩次連 spec 都沒過。

AI 寫同一個 app,十二種框架的帳單

Nolan Lawson 在 2026 年 10 月 28 日發表的這篇文章,起點是一句抱怨:「One of my pet peeves with the web development community is that so many of the decisions we make are vibes-based.」前端選型靠感覺,這件事他早就看不慣;AI 開始替人寫程式之後,他說自己仍然看到「vibes ruling the day」。於是他做了一個實驗,把「哪個框架讓 AI 寫起來比較省」這個問題,換成能重跑、能並排比較的數字。

實驗的骨架很單純。一份 spec,要求做出一個以 PokéAPI 為資料來源的 Pokémon app;十二種起點,包含 Angular、Astro、Gracile+Lit、Hono+htmx、Next.js、Nuxt、Qwik、React Router、SolidStart、SvelteKit、TanStack Start,以及不用框架的 Vanilla Vite;每種跑五次,取中位數。量的東西分兩邊,一邊是 AI 開發時花了多少,包括費用、時間、token 與程式碼行數,另一邊是產出的 app 長什麼樣,包括 JS 體積與 Lighthouse 分數。

先把全貌放在眼前。下圖用文章報告的中位數畫出十二組,按鈕切換指標,每條橫條上的細線是五次之間的最小值到最大值。預設是開發費用,由低排到高:最低是 Hono+htmx 的 US$2.67,最高是 Angular 的 US$4.97。

點按鈕切換指標 · 7 項指標 × 12 組框架

0 1 2 3 4 5 6 7 Hono+htmx$2.67 Astro$2.76 Nuxt$2.82 Vanilla$2.98 Next.js$3.14 Qwik$3.27 TanStack Start$3.54 SolidStart$3.79 React Router$3.81 SvelteKit$4.28 Gracile+Lit$4.65 Angular$4.97 開發費用(US$,Claude Code 顯示的 API 牌價)

最低是 Hono+htmx 的 $2.67,最高是 Angular 的 $4.97,約 1.9 倍。細線是五次(Angular 部分指標為三次)的最小到最大。

資料:Nolan Lawson 文章中的中位數與括號內範圍,所有指標都是越低越好。排序依中位數,不依範圍。

這張圖有兩點值得先記住。換指標,排名會換位置:費用最低的 Hono+htmx 在 JS 體積上排第四,JS 體積幾乎為零的 Astro 在費用上排第二,Gracile+Lit 的 JS 只有 8 KiB,開發費用卻是第二貴。另一點是細線的長度,Angular 的費用範圍從 3.19 拉到 6.82,Hono+htmx 只有 2.23 到 3.19。這個長度後面會變成一整節的主題。

方法與它自己承認的限制

spec 的開頭是「Design a small but non-trivial Pokémon app using the PokéAPI.」作者給 agent 的指示也盡量少:「I simply gave the spec to Opus 5.5 with high effort and told it to use the latest version of the given framework.」換句話說,沒有針對框架客製提示,只指定模型、effort 與「用最新版」。repo 的 README 把 prompt 寫成兩句:Implement the app described in SPEC.md using **{framework}**. Use the latest stable version.以及另一行 Work autonomously until `npm test` passes.

要讓十二種寫法能用同一套標準驗收,測試的設計是關鍵。作者說 app 要通過一組 conformance suite,這組測試「based on the accessibility tree rather than the raw DOM」。合理的推測是,各框架產生的 markup 結構不同,若比對原始 DOM,測試會偏袒某種寫法;改看 accessibility tree,測的就只剩使用者與輔助技術真的看得到的東西。這是對設計動機的推測,文章沒有明說。作者還提到有一件他不希望 agent 做的事,他「specifically forebade that in the instructions and made it an explicit check in the test harness」,也就是指示裡明文禁止、測試裡再加一道明確檢查。

重複次數與失敗處理也寫得很清楚。「For each framework/meta-framework, I took the median of 5 runs」;例外是 Angular,它「failed to create a measurable app twice, so I took 3 iterations instead for some metrics」。其中兩次失敗,作者的說明是 agent 做出了一個「SSR app that rejected non-localhost」,而 spec 預先交代過 app 會放在 reverse proxy 後面,所以這兩次算違反 spec,沒有重跑。換言之,Angular 那一列的部分指標只有三次樣本,看它的範圍時要把這點算進去。

費用欄需要一個提醒。作者寫明這些數字「quotes the API prices directly from Claude Code and doesn't actually represent how much money I spent」,它是依牌價折算的帳單,不是他實際付的錢。拿來比較框架之間的相對高低可以,當成預算估算就要小心。各框架提供的 MCP 與 skill,使用情形也不一致:以 Nuxt 為例,作者說它的 MCP「was never used by the agents」。作者的看法是,這正是實驗要的真實情況,因為他不認為「many vibe-coders are shouting at their agents in all-caps」要求使用 MCP,預設行為才是多數人遇到的基準。

限制部分,作者自己講得比多數評論者直接。「this is not a perfect experiment」;測試用的 app 只是「one holotype」,是內容為主、互動很少的網站,他形容更接近 Wikipedia 而不是 Figma 或 GMail,選它是因為相對容易寫 spec 與測試;Lighthouse 只報首頁分數;而他在跑完之後的體會是「everything I’m measuring is very stochastic」。README 對這點說得更短:「One iteration is an anecdote.」這幾句放在一起,等於替整篇文章劃了適用範圍,後面每一個排名都該在這個範圍內讀。

這些限制疊在一起還有一層讀法:費用是牌價折算,MCP 與 skill 的使用不一致,Angular 部分指標只有三次樣本。因此表上的每一格,都混著工具使用習慣與樣本數,不只是「框架效應」。

開發成本:token、時間、費用與程式碼量

AI 替你寫一個 app 要花多少,文章用四個欄位回答。費用中位數由低到高,前三名是 Hono+htmx 的 US$2.67、Astro 的 US$2.76、Nuxt 的 US$2.82;最後三名是 SvelteKit 的 US$4.28、Gracile+Lit 的 US$4.65、Angular 的 US$4.97。Next.js 是 US$3.14,落在偏前段。最貴與最便宜相差的幅度,按表上的數字算約 86%,不到一倍。

時間與 token 的排序和費用並不一致。Astro 的中位數是 8.2 分鐘,最快;Hono+htmx 是 8.6 分鐘,卻是費用最低。token 用量最少的是 Nuxt,中位數 3.85M,最多的是 Angular 的 9.76M,Gracile+Lit 的 9.04M 與 SvelteKit 的 8.53M 緊跟在後。Angular 的時間中位數 17.2 分鐘也是十二組最長。四個開發指標裡,Angular 的費用、時間、token 與程式碼行數都是最高,這是整張表最一致的訊號。

程式碼量最少的是 Hono+htmx,中位數 1370 行,Angular 最多,2009 行。作者在文章裡提到 Hono+htmx 能「do roughly the same thing as Angular with ~70% of the code」;按表上的兩個中位數相除是 0.68,和他的說法對得上。不過要注意,行數是 agent 寫出來的量,它同時反映框架樣板的多寡與 agent 的寫法,不能直接當成人類維護成本的指標。

SvelteKit 的位置最值得停一下。它的時間中位數 10.8 分鐘在十二組裡只算中間,token 卻高到 8.53M,費用因此排進前三貴。作者給的解釋是,agent 在每次執行時都會去讀 SvelteKit v3 的遷移指南,而這份指南可能新到不在 Opus 5.5 的訓練資料裡。這是作者的推測,不是他驗證過的結論。若推測成立,這筆帳反映的是模型知識截止點與框架版本節奏的錯位,下一代模型或下一個版本出來,數字可能整個換位。

Nuxt 則是另一種故事。token 最少、費用第三低,但五次裡最慢的一次花了 17.6 分鐘,超過 Angular 的時間中位數 17.2 分鐘。中位數把這種長尾壓平了,單看一列數字會漏掉它。這也是為什麼上面那張圖要把範圍一起畫出來。

把 Hono+htmx 整列讀完:費用最低的 US$2.67、程式碼最少的 1370 行、JS 體積 18 KiB,LCP 中位數 978 毫秒。四個數字都在好的一端,但它的 LCP 範圍上限是 1662 毫秒,和 Astro 的上限相同。

出貨成本:JS 體積與 Lighthouse

開發花多少是 AI 的帳,產出的 app 重不重是使用者的帳。JS 體積從 Astro 的 0 KiB(五次範圍 0 到 1)起跳,接著是 Vanilla 的 7 KiB、Gracile+Lit 的 8 KiB、Hono+htmx 的 18 KiB;中段是 SvelteKit 36 KiB、SolidStart 與 Qwik 各 40 KiB;偏重的是 Nuxt 84 KiB、Angular 93 KiB、React Router 115 KiB、TanStack Start 118 KiB,最重的是 Next.js 的 142 KiB。最輕與最重之間的差距是 142 KiB。

把這個維度和上一節的費用擺在同一張圖上,會得到一個沒有對角線的散布。開發最便宜的三組,Hono+htmx、Astro、Nuxt,JS 體積分別是 18、0、84 KiB,跨度相當大;開發偏貴的 Gracile+Lit 反而只有 8 KiB。看完這張圖,比較站得住腳的結論是:開發時 AI 花得少,並不保證出貨的東西輕,兩者要分開看。

0 50 100 150 2.5 3.0 3.5 4.0 4.5 5.0 開發費用中位數(US$) JS 體積中位數(KiB) Hono+htmx Astro Nuxt Vanilla Next.js Qwik TanStack Start SolidStart React Router SvelteKit Gracile+Lit Angular
每個點是一組框架的兩個中位數。左下角代表開發便宜、出貨也輕,圖上這個角落有 Astro、Vanilla 與 Hono+htmx;Nuxt 開發便宜卻出貨偏重,Next.js 出貨最重,Gracile+Lit 開發偏貴卻出貨很輕。

Lighthouse 的部分,答案比預期無聊。八組的 Performance 是 100,Vanilla 是 97、Angular 98、TanStack Start 與 Next.js 各 99;Accessibility 十二組全是 100;CLS 除了 Vanilla 的 0.111 之外都是 0.000。作者也強調這些分數只報首頁。分數幾乎飽和,意味著用它來分高下的力氣不大,真正拉得開差距的是 LCP 與 TBT:LCP 最短的是 Astro 的 810 毫秒,最長的是 Next.js 的 2090 毫秒;TBT 多數接近 0,Angular 是 103 毫秒,Next.js 是 71 毫秒,Nuxt 是 40 毫秒。

Lighthouse 中位數(行動版,首頁),依 JS 體積由小到大排列
框架PerfA11yCLSLCP msTBT ms
Astro1001000.0008100
Vanilla971000.11116670
Gracile+Lit1001000.0009560
Hono+htmx1001000.0009780
SvelteKit1001000.00011300
SolidStart1001000.000120411
Qwik1001000.0009793
Nuxt1001000.000172740
Angular981000.0001954103
React Router1001000.000172917
TanStack Start991000.00020281
Next.js991000.000209071
灰字是飽和或接近 0 的格子,橘色底是沒到滿分的分數或較大的延遲。前三欄幾乎一片灰,差異全擠在後兩欄。

作者對這些數字的警告很直接:Lighthouse 與 Core Web Vitals「are biased against SPAs, so the MPA frameworks are almost guaranteed to win」。這就是為什麼 Astro 與 Hono+htmx 的 LCP 和 TBT 漂亮得不太意外。他也看到 Astro 與 Vanilla 的 LCP 範圍有大幅擺動,說這「appear to be caused by prioritization or LCP quirks」。Astro 的 LCP 中位數是 810 毫秒,範圍卻是 792 到 1662;Vanilla 是 1667 毫秒,範圍 764 到 1676。同一個框架在五次之間能跳出一倍的 LCP,單次量測的意義就很有限。

還有一個沒被這些指標抓到的面向。README 的說法是,測試只量頁面載入,沒有量載入之後的互動,而 SPA 可能在後者表現得比較好;這個測試的 app 又是內容為主、互動很少,Lighthouse 量的還只是首頁。README 同時寫明資料必須在請求時向 API 取得,所以建置時預先產生頁面繞不過 API。這些設計讓結果更貼近這份 spec,但並沒有讓它更貼近你的產品。

噪音:中位數底下的區間

前面兩節都在讀中位數。這一節問另一個問題:框架之間的差距,比同一個框架自己五次之間的波動大多少?作者說「everything I’m measuring is very stochastic」,下圖把這句話量化。每一條是一組框架的費用範圍(最大減最小)占它自己中位數的比例,由大到小排列;虛線是最貴與最便宜兩個中位數之間的差距,86%。這是依文章表格算出來的衍生數字,不是作者報告的欄位。

0% 20% 40% 60% 80% 100% 最貴與最便宜的中位數相差 86% Angular73% Nuxt66% Astro53% SolidStart52% Next.js49% Qwik44% Vanilla38% Hono+htmx36% React Router30% SvelteKit25% Gracile+Lit25% TanStack Start24%
費用範圍占自身中位數的比例,計算方式為(最大值減最小值)除以中位數。Angular 只有三次樣本,該列的比例比其他列更不穩。

圖上最直接的讀法是:Angular 單一框架內部的 73% 波動,已經接近跨框架的 86% 差距。把範圍直接拿來比,效果更明顯。Angular 五次裡最便宜的一次是 3.19,剛好等於 Hono+htmx 最貴的一次 3.19;Next.js 的 2.58 到 4.13,整段蓋住 Hono+htmx 的上半部。費用中位數前六名,Hono+htmx、Astro、Nuxt、Vanilla、Next.js、Qwik,它們的範圍全都包含 2.58 到 3.19 這一段,也就是說在這個樣本量下,六組之間的排序並沒有被資料明確分開。

時間的長尾更誇張。Vanilla 的時間中位數是 10.1 分鐘,最慢一次 18.6 分鐘;Nuxt 的最慢一次是 17.6 分鐘。如果某個專案只跑一次,抽到這兩個框架的長尾,結論就會是「Nuxt 比 Angular 慢」。這不是在說作者的統計做錯,他取五次中位數,本來就是為了擋掉這種誤判;問題在於讀者拿到的往往只是排名表,範圍藏在括號裡,沒有人會一個個去對。README 那句「One iteration is an anecdote.」放在這裡就不只是謙遜,而是操作建議:不到三次的重跑,結論可以先擱著。

反過來看,也有被資料明確分開的差距。SvelteKit 最便宜的一次(3.59)高於 Hono+htmx 最貴的一次(3.19),Gracile+Lit 最便宜的一次(3.92)更高;這兩組的費用不是靠運氣抽到的。Angular 的費用、時間、token 與行數四欄都排最後,而且是四欄同時,這種一致性比任何單一欄位的名次都更能說服人。因此,能被資料支撐的結論集中在最貴的一端;最便宜的一端與中間那一大段,沒有明確排序。

token 的波動同樣驚人。Angular 的 token 範圍從 4.92M 到 14.94M,最高的一次約是最低的三倍,費用跟著從 3.19 拉到 6.82。對預算來說,這代表同一個選擇可能帶來差很多的帳單。

該怎麼選:證據能支撐的與不能支撐的

先把可以說的列出來。資料明確分開的是貴的那一端:在這份 spec 與這個模型下,Angular 在四個開發指標上都最高,而且有兩次產出未通過 spec,雖然部分指標只有三次樣本;SvelteKit 與 Gracile+Lit 最便宜的一次,也都高於 Hono+htmx 最貴的一次。若你的團隊在乎 AI 輔助開發的成本,這是實打實的訊號。Hono+htmx 與 Astro 的中位數排在低端,出貨體積也落在好的一端,但它們和 Nuxt、Vanilla、Next.js、Qwik 的範圍互相重疊,這份資料沒有把它們分開,何況作者明說 Lighthouse 偏向 MPA。另外,開發便宜與出貨輕是兩件事,上面那張散布圖已經示範過。

再列不能說的。TanStack Start、SolidStart、React Router、Next.js 這幾個中段框架之間,文章的資料沒有足夠的分辨力,範圍重疊得太多。文章報告的指標也沒有包含人類維護程式碼的成本、團隊熟悉度、招募市場或生態系;一份只有費用、時間、token、行數、JS 體積與 Lighthouse 的表,回答的是「AI 寫起來多貴、產出多重」,不是「你該用什麼」。作者自己也說 app 是「one holotype」,如果你做的是 Figma 那一類的產品,這些排名能搬多少過去,文章沒有給依據。

還有一類結論連作者都只給了猜測。他說:「I have a strong suspicion, for example, that the current crop of MCPs and skills may be doing more harm than good.」這是一個用「suspicion」與「may」包起來的懷疑,我們也只能照這個強度轉述。同樣地,SvelteKit 貴在讀遷移指南的說法,是他的推測。若這個說法成立,換一個訓練截止點不同的模型,同一個框架的帳單就可能移位;文章沒有直接驗證這一點,這裡只是把它標出來。

那團隊該怎麼辦?文章的結尾其實給了方向:「it's possible in the era of AI coding to still make decisions based on evidence rather than vibes」,並且丟出一個問題:「Are you really picking your tech stack based on evidence?」把這個問題拆開,先承認自己手上的證據是什麼:是這篇文章的某個排名,還是你自己用過的經驗?再把你的產品形狀放進去對照,內容為主還是互動為主,決定了 Lighthouse 偏向 MPA 的那部分偏見對你重不重要。最後才是自己跑一次。作者鼓勵大家:「if anybody wants to run the benchmark themselves or fork it, it’s on GitHub, so I encourage you to go nuts.」repo 的 README 提供了跑法,指令範例是 node bench/run.mjs --frameworks=all --iterations=3;同一份 README 也註明專案本身是 AI 生成的,而且 PRs 是關閉的,所以想改動就得 fork,不是送 PR。

自己重跑時,最費力的環節大概不是 harness。作者挑內容型 app,是因為它相對容易寫 spec 與測試;換成你的產品,寫出可驗收的 spec 與 conformance suite 大概才是主要工作量。

下面的小工具把「你自己的權重」放進去,看看排名怎麼動。它只用兩個欄位:費用中位數與 JS 體積中位數,各自在十二組之間縮放到 0 到 1,分數越低越好。這是本文加的算式,用來示範「換一組權重,名次就換一批」,不是作者的評分,也不是推薦。

拖曳滑桿改變權重 · 2 個欄位 × 12 組框架

費用 50%/JS 體積 50%
    分數 = 費用權重 × 費用縮放值 + JS 權重 × JS 縮放值,縮放值為(該組數字減最小值)除以(最大值減最小值)。資料來自文章的中位數,不含五次範圍,所以相鄰名次的差距常常小於雜訊。

    分數 = 費用權重 × 費用縮放值 + JS 權重 × JS 縮放值,縮放值為(該組數字減最小值)除以(最大值減最小值)

    只看開發費用是 Hono+htmx 最低,只看 JS 體積是 Astro 最低;兩者各占一半時 Astro 居首,Hono+htmx 次之,名次隨權重移動。

    把滑桿推到 100%,只看開發費用,榜首是 Hono+htmx;推到 0%,只看 JS 體積,榜首是 Astro;停在 50%,Astro 居首、Hono+htmx 次之,Vanilla 緊跟在後。這沒有告訴你該選誰,它告訴你的是:先決定自己在乎的是哪一邊,再看表。多數團隊的真實權重不會是 50 比 50,也不會只有這兩個欄位。

    落到行動上,大概是這樣分流。如果你的產品是內容為主的網站,又正在評估 AI 輔助開發的成本,這份資料只能提醒你,Angular、SvelteKit 與 Gracile+Lit 的帳單偏高,要先問自己為什麼需要它們;Hono+htmx 與 Astro 的中位數在低端,可以放進比較名單,但要和另外四組一起比;如果你的產品是重互動的應用,這份資料幾乎無法替你做決定,因為作者自己講明了測試對象不是那一類。無論哪一種,拿到結論之前先自己重跑三次以上,再看範圍而不是只看中位數。

    How to choose:這份資料只能支撐貴的一端,Angular 在四個開發指標上都最高,SvelteKit 與 Gracile+Lit 的最低一次也高過 Hono+htmx 的最高一次;中位數最低的 Hono+htmx 與 Astro 並沒有和其餘各組分開,名次被五次之間的雜訊蓋過,真要選就用自己的 spec 重跑至少三次。