The 2026 Frontend Infra Map: The Real Battleground Is AI's Verification
After the Rust rewrite and the great unification, frontend infra's center of gravity is shifting from catching human errors to catching AI's — and what that means for CI, verification, and the IDP.
這篇是我在 v-taiwan 那場《Modern Frontend Infra》talk 的文字版。

整場分成五段,這篇也照同樣的順序走:

從兩樁收購說起
最近前端圈有兩件收購案。如果你平常有在追工具鏈的消息,看到大概會愣住一下。
- 2026 年 6 月:Cloudflare 把 VoidZero 買走了,那是尤雨溪開的公司,專門在做下一代的前端工具鏈
- 2025 年底:Anthropic,對,就是做 Claude 的那家 AI 公司,把 Bun 給收了

這類型的產品,以前是不太會有人來買的。
為什麼?因為前端的打包器、linter、執行環境,過去就是一個個開源專案,作者用愛發電,頂多接受一點贊助。
然後現在呢,平台級的大公司開始掏錢來搶,而且半年內就兩件。
把這幾件事連起來看
收購本身我沒那麼在意。它們背後指向的同一件事才是重點:前端的基底正在悄悄換血。
把最近兩年的幾件事排在一起看,你大概就有理解了:
| 時間 | 事件 |
|---|---|
| 2024-10 | 尤雨溪在 ViteConf 宣布成立 VoidZero |
| 2025-10 | Vite+ CLI 亮相 |
| 2025-12 | Anthropic 買下 Bun |
| 2026-03 | Vite 8 把 Rolldown 變成預設打包器 |
| 2026-06 | Cloudflare 買下 VoidZero |

一件一件單看好像還好,連起來就很難說是巧合了。
所以這篇想做的,就是順著這條線,把 2026 的這張新地圖畫出來。
這對前端來說有什麼影響?
我猜有些人會想:Infra 那不是平台團隊在弄的嗎?我平常都在寫 feature,這對我有什麼影響?
你 git push 之後,發生了什麼事?
我換個方式問你好了。你今天寫完一個元件 git push 上去,接著會發生什麼事呢?
背後有一大坨東西自動跑了起來:
- 幫你檢查風格的 lint
- 看型別的 type check
- 跑測試
- 打包
- 更完整的甚至幫你開一個預覽網址讓同事 review

而那一坨就是 infra。
你每天都在用它,只是通常只有在它很慢、或是擋著不給你 merge 的時候,才會想起它的存在以及重要性。
Infra 一直只解決兩件事
那要怎麼看懂這張地圖?我自己是抓一個很簡單的框架。
前端 Infra 從以前到現在,一直只在解決兩件事:
- 重複:那些每次都要做、又很容易漏掉的事,交給機器做
- 錯誤:在問題進到正式環境之前,先把它擋下來
重複性
自動化重複勞動錯誤
攔截錯誤這兩條,一條幾十年來幾乎沒變過。另一條,正在我們眼前整個翻轉過來。
而今天的主角就是後面那條。

上面這張就是我當天開場用的投影片。重複那條寫著 unchanged for decades,錯誤那條寫著 flipping right now。整場我就是在講後面那一條。
Infra 一直在做兩件事:自動化重複、攔截錯誤。重複那件沒變,變的是我們從攔「人」的錯,變成攔「AI」的錯,而 AI 的錯,多到只有機器攔得住。
講到這我想提一下 Kyle。
他 2023 年寫過一篇很多人轉的《成為前端建築師吧》,把 Frontend Infra 講得很完整,也給了一個我很喜歡的定義:
Infra 就是「為了提升開發效率跟產品品質,而導入的一套系統、流程跟工具」。
這個定義先擺著。因為他那篇 2023 年的文章,剛好就是我們今天要拿來對照的「過去」。
而在 2023 年,Infra 攔的是人的錯。 這句話你先收著,等一下會回來繼續解析。
三波,同一個目標
接下來就順著三波走。先給你一張路線圖,你會發現這三波都在對同一件事下手,就是「驗證」。
2026 前端 Infra 路線圖

- 第一波讓驗證變便宜到你敢一直跑
- 第二波把跑滿的驗證變成沒缺口的護欄
- 第三波把這片護欄轉過來,對準真正的目標:AI 的錯
一路讀下來,你就會看到「驗證」怎麼一步步被推成戰場。
第一波:Rust 化,重點不是快,是便宜

一場全面的世代交替
過去一兩年,你可能聽過 Oxlint、Rolldown、Vite 8 這些名字。
它們表面上各做各的,底層卻藏著同一件事:都改用 Rust 重寫了,不再是 JavaScript。
攤開來看,這是一場滿全面的世代交替。每一個舊的 JS 工具,都被一個新的原生語言工具接手。
世代交替
JS 工具 → 原生語言工具你等過 ESLint 嗎?
先從一個大家都有的經驗開始。
terminal — 中大型專案的日常(示意)
$ npx eslint .
⠹ Linting 2,847 files...
⠼ Linting 2,847 files... ← 跑去倒了杯咖啡
✔ Done in 38.2s38 秒不算長,但足夠讓你切去做別的事,回來還要想一下剛剛在幹嘛。
同一個專案換成 Oxlint,官方 benchmark 是 50–100 倍。
我自己的 monorepo 用 vp lint 跑 Oxlint,0.39 秒全部掃完,快到我第一次還以為它根本沒跑!

重點不是「快」,是「便宜」
這一波的數字大致是這樣:
| 舊工具 | 新工具 | 幅度 |
|---|---|---|
| ESLint | Oxlint | 50–100× |
| Rollup + esbuild | Rolldown | build 10–30×,記憶體少 75% |
| tsc | TypeScript 7(Go 重寫) | type check ~10× |
先聲明,這些都是別人公布的數字。
Vite 8 官方說把預設打包器換成 Rolldown 之後,生產環境的 build 比 Rollup 快了十到三十倍。而且不是實驗室裡那種漂亮數字:
- Linear:build 46 秒 → 6 秒
- Ramp:縮短 57%
- Mercedes-Benz:縮短 38%
- Beehiiv:縮短 64%

同一頁也提到,用 Oxc(Rust 寫的那顆共用 parser 核心,等一下第一波會細講)的語意分析,幫 Rolldown 做更準的 tree-shaking,也就是把你沒用到的程式碼從 bundle 裡自動搖掉、不打包進去。
然後這股重寫潮還燒出了 JS 工具鏈的範圍,連語言層都動了。微軟在 2026 年 7 月正式發布 TypeScript 7.0,把整個編譯器用 Go 原生重寫,type check 快了大約十倍、build 快八到十二倍。

有趣的是,它選的是 Go 不是 Rust。
所以這一波的重點不在 Rust 本身,在原生重寫這個動作。當連 TypeScript 這種等級的工具都被整個重寫,你大概就知道這波是玩真的了。

為什麼可以這麼便宜?
如果你只看到「快」,我覺得就會錯過真正有意思的地方。
一部分確實是語言本身。Rust 沒有垃圾回收造成的停頓,記憶體用量可預測,又能吃滿多核,這些是 JavaScript 先天做不到的。
但更關鍵的,是架構。
你想想以前的專案:ESLint 解析一次程式碼、Prettier 再解析一次、tsc 又解析一次。同一份檔案被拆成語法樹拆了三四遍,每個工具都在重造輪子。
Oxc 這類工具反過來,讓 parser、linter、formatter、transformer 共用同一套解析跟語意分析。一份 code 只拆一次,後面大家接著用。省下來的就是那幾十倍。
舊世代
同一份 code 被 parse 三遍Oxc 世代
parse 一次,大家共用上層是舊世代,同一份 code 被 parse 三遍。下層是 Oxc,只 parse 一次、三個工具共用同一份結果。

infra 的第一軸「消滅重複」,這次用在了 infra 自己身上。
所以快只是表面。底下真正發生的是,跑一次完整驗證的成本整個被顛覆了。
以前跑一輪完整的 lint、type check、build 是要精打細算的:吃 CPU、吃時間、吃 CI 費用。算力在過去是稀缺資源,每次驗證都要評估值不值得。
可是當一次 lint 從一兩分鐘掉到幾百毫秒,事情就不一樣了。你可以在每次存檔、每個 commit、每個 PR 都跑一遍,卻完全不心痛。
於是一個平常被成本壓著、根本沒機會問的問題,就冒出來了。
省下的算力,你要拿去「省錢」,還是拿去「驗證更多」?
這個問題你先擱著,它是後面兩波的引擎。
誠實的缺口:Oxc 只讀得懂半個 .vue
不過這件事還在發酵中,不用急著更換。
Rolldown 現在 dev 模式吃的記憶體反而比較高,這是已知問題、也還在調整。更精確的講法是:它 build 快得很誇張,但整體還在成熟的階段。
日本團隊 ANDPAD 把這些工具真的放進生產環境用過。
格式化工具 Oxfmt:純 JS/TS 快了 48 倍,連 Vue 檔案一起算也還有約 4 倍,而且跟 Prettier 100% 相容。他們的結論是現在就能換掉,一點問題都沒有。
但 linter 那支 Oxlint 還沒辦法完全取代 ESLint。.vue 它只吃得下 <script> 那一半,template 還讀不懂。
務實的做法:格式化整碗端走,檢查先混著用。
方向很確定,但你真的不用今天就全部換掉,也不用太焦慮學習上的問題。
我的建議: 過渡期走雙軌並行,這在 JSDC 2025 那場也給過同樣的答案。
- Oxlint 先吃掉九成的常見規則(速度)
- 剩下的 plugin 規則留給 ESLint 殿後(生態完整)
- 等 Oxlint 規則補齊,再把 ESLint 整個退役

而 Vue 這塊已經有人在補洞了。
Vue core 的 ubugeeei 做了一個叫 vize 的 Rust 工具鏈:一份 parser 專門吃 .vue,同時餵編譯、lint、格式化、型別檢查跟 LSP。
等於把上面那套「共用 parser」的邏輯原封不動搬進 Vue。它甚至還做了 oxlint plugin 能掛進 Oxlint 一起跑,兩邊是互補,不是對打。

vize 自己的數字:便宜,不是快
它自己的 benchmark 剛好是個很乾淨的例子(專案自測,樣本 15k 個 SFC,也就是 .vue 單檔元件):
| 項目 | 幅度 |
|---|---|
| lint | 209× |
| SFC 編譯 | 55× |
| 格式化 | 68× |
| end-to-end build | 1.1× |
檢查快到誇張,最終 build 幾乎沒動。

這張是我當天講 vize 用的投影片,下面那句就是整個第一波的靈魂:
檢查沒有變「快」,是變得「便宜到可以隨時跑」。
但它一樣還在實驗、是個人專案。VOICEVOX、Misskey 已經拿去當白老鼠。它展示的是方向,不需要現在就換。
先埋一個伏筆:結構越乾淨,機器越幫得上忙
在進第二波之前,我想先埋一個之後會用到的伏筆。
這些 Rust 工具除了快,還能更準地做 tree-shaking,把沒用到的程式碼搖掉。但有一個東西會擋住它,叫循環相依。
當 A 依賴 B、B 又回頭依賴 A,模組的邊界跟副作用就變得很難靜態判斷。工具沒把握「刪了會不會出事」,只好保守地留著。
結論很單純:結構越乾淨且清晰,機器越幫得上忙。
這句話在第三波會突然變得很重要。
第二波:統一化,CI 從「省」變成「守」

2023 年,你得自己當膠水
我們回來看 Kyle 2023 年那篇文章。
裡面有一張圖我印象很深,是他幫一個專案建 infra 時,要親手接的工具。
2023・一個專案的前端工具鏈
每一個都要自己裝、自己設定、自己接每一個都要單獨裝、單獨設定、單獨維護,還要想辦法讓它們彼此相容。
光是把這堆黏在一起又不打架,就是一份全職工作了。
這就是當年前端 Infra 的樣子:一堆工具各自維護,你自己是那個膠水。
Vite+ 團隊的 naokihaba 講過一句我覺得很到位的話:在做出產品之前,我們其實一直在做的,是工具鏈。
想想也是。有時候都還沒開始寫產品功能,光是把這十幾個工具挑好、設定好、再讓它們彼此相容,就先耗掉一大段力氣。
而且選完還不算完。Prettier 要換 Oxfmt、ESLint 要換 Oxlint、Jest 要換 Vitest。工具自己一直在進化,你得一直追著換。
2026 的答案:一套統一的工具鏈
2026 的答案就是統一化,把這十幾個工具收斂成一套。
被 Cloudflare 收購的 VoidZero 做的就是這件事。我自己在用的 vite-plus 也是,它把 Node 版本、套件管理器、加上打包測試檢查那一整套,全部收進一個 vp 指令底下。

這個方向對我來說也不是新聞。去年 JSDC 的未來展望我就介紹過 VoidZero,當時 Vite+ 才剛亮相、還在願景階段。一年後就變成我每天在用的日常。未來比想像中來得快。

上圖是 Vite+ 官網,一個 vp 指令從 create、dev、check、test 到 build 一條龍。
我自己每天就在打 vp run、vp check,lint、打包、測試一次收工。說真的蠻省事的。
先聲明一下:它上個月才剛進入 beta、開源免費,還在成熟的路上。建議你可以先觀望,但方向就是這個沒錯。
而且它管的不只是工具,還有整個環境。
你 vp create 的當下,它就順手鎖好這個專案要用哪個版本的 Node、哪個套件管理器。於是「在我機器上會動、在你機器上壞掉」這種經典災難,有機會直接消失。因為本機跑 vp check、CI 也跑 vp check,兩邊是同一組指令、同一套版本。
這也不是我一個人在自 high。VoidZero 官方的六月回顧提到:
- 自 alpha 以來合併 500+ 個 PR
- 修了 180+ 個問題
- 已有超過 1,300 個公開專案在用它

上圖是那篇官方回顧。Vite+ 進入 beta、一千三百多個專案採用,連 Vite+ 自己都改用 Vite+ 來 build。
而且這不是一座孤島,連框架都在往同個方向靠:
- Astro 7 已經內建 Vite 8
- Nuxt 4 的下一個小版本也要跟上
- 甚至冒出一個叫 Vinext 的 Next 相容框架,底層走的一樣是 Vite
整個生態在收斂,不是某個小圈子的偏好而已。
NX 到底要不要學?
講到這,我知道有些剛入行的朋友可能開始焦慮:天啊又一堆工具,NX 我到底要不要學?

我直接說結論:在 Vue 的生態裡,你多半不需要學 NX。
Vue 社群的核心走的都是「輕量、可組合的小工具」這條路,不是重型框架。所以聽不懂 NX 真的沒關係,那不是你現在該擔心的東西。
更具體一點的門檻是:10 個 package 以下,pnpm + Oxlint 就已經夠了。
兩個陣營,相反的哲學
但統一化真正有意思的地方,我覺得不在「少打幾個指令」,而在一個哲學上的反轉。
解決「工具碎片化」這件事,市面上大致分成兩派,哲學剛好相反:
| 陣營 | 代表 | 主張 |
|---|---|---|
| 平台派 | NX | 一個平台把專案關係圖、任務快取、程式碼產生器、CI 整合全包進去,像全家桶 |
| 組合派 | pnpm · Oxlint · vite-plus | 一堆小而專、可自由組合的工具,像樂高 |

這兩派怎麼選,那場《Modern Monorepo Toolchain》我用了一整段在聊。
當時主流的答案還是 pnpm 配上 Nx 或 Turborepo 二選一。結尾我還許了一個願,很期待 Vite+ 能把工具鏈再收得更攏、甚至取代掉 Nx 跟 Turborepo。
半年後回頭看,這個願正在成真的路上。這篇也算接著那場往下走,從「怎麼選工具」走到「工具為誰而守」。

CI 的哲學反轉:從「省」到「守」
拿 NX 來對照最清楚。
NX 有個招牌功能叫 affected:它會建一張專案的相依圖,算出這次改動只影響哪些部分,然後只跑那些,其他直接跳過。
為什麼要跳過?因為省啊。在算力貴的年代,能少跑一點就少跑一點。
vite-plus 的做法正好倒過來:它全部都跑,只是靠快取,讓沒改過的部分瞬間完成。
這兩種做法的差別,不只是速度,還有正確性:
NX affected | vite-plus「全部跑 + 內容快取」 | |
|---|---|---|
| 怎麼省 | 算相依圖,只跑受影響的 | 全部跑,快取讓沒變的瞬間完成 |
| 正確性前提 | 那張圖必須是對的 | 快取金鑰 = 輸入檔案 + 設定 + 工具版本的雜湊 |
| 失效模式 | 隱性相依、設定檔漂移、跨專案副作用讓圖算漏,該跑的檢查被悄悄跳過,而你不會知道 | 內容一樣才命中,任何一點不一樣就重跑,不會漏驗 |
它只是把「沒變的東西」變便宜,而不是賭它沒事就跳過。
快取命中長這樣,這是我自己 repo 的實際輸出:
第二次跑 — real capture
$ vp run utils#build
✔ Build complete in 112ms
vp run: cache hit, 695ms saved.
這也不是空談。VoidZero 那篇回顧裡就有個很妙的例子:Vite+ 這個專案本身現在就是用 Vite+ 來 build 的,光靠快取,整條 pipeline 就少了大約一成的時間。
等於工具自己就在示範這套哲學,不是靠賭跳過來省,而是靠「全部跑 + 快取」,既快又完整。
快取的甜頭我自己也吃過。
真實案例: 我們團隊導入 Remote Cache 之後,同一條 pipeline 從 45 分鐘壓到 8 分鐘,效率提升 82%。
原理就一句:別人跑過、輸入又沒變的任務,直接拿結果來用,不要再跑一次。而且 monorepo 越大,這個價值越高。

這就是第一波那個引擎問句的答案。
算力貴的時候,我們用 skip 來省錢。算力便宜之後,我們反而寧可全部跑一遍,把 CI 當成一整片沒有缺口的護欄。
CI 的哲學,從「少跑、省錢」,變成了「跑滿、當護欄」。
護欄在野外長什麼樣:20 支 workflow
這套「跑滿當護欄」的哲學不是紙上談兵。
我把 vite-plus 官方 repo 的 CI/CD 整個拆開來讀。做工具鏈的人,自己就是這樣過日子的。
攤開 .github/workflows 一共 20 支,照用途分是這個比例:
| 類別 | 支數 | 內容 |
|---|---|---|
| Verify | 7 | ci · e2e · security · docker · standalone-install · vp-create · binary size |
| Dependencies | 3 | upgrade-deps · renovate-lockfiles · node-release-keys |
| Cache | 1 | cleanup-cache,一整支 workflow 只為了快取衛生 |
| Release · docs · 社群 | 9 | prepare → release → build → 人工核可 · 文件部署 · issue bots |

我另外照「一個改動的生命週期」排了一次,看得更清楚:
PR 一開就跑
pull_request合併之後
push · PR closed排程與維運
cron · issues發版鏈
release還記得前面 Kyle 那張清單嗎?這張長得有點像,方向卻剛好相反。
那張是你得自己當膠水接起來的工具,這張是自己會跑的護欄。
連「安裝流程」「create 體驗」「native binary 的大小」都有專屬驗證,每個 PR 都會跟 main 比一次 binary 有沒有變胖。
這種密度在以前是燒不起的。oxc 讓驗證變便宜之後,這些自動化才從奢侈品變成日常。
這個 repo 先記著,等一下實踐那段會回來看它最精彩的一支。
低調的骨幹:pnpm
順帶一提,統一化也還在默默處理那條沒變的重複軸。
pnpm 為什麼又快又省?因為它用 symlink 把每個套件指向硬碟上同一份內容,而不是每個專案各複製一份。
一百個專案用到同一版的 lodash,硬碟上也只存一份。你看,又回到第一軸了。
它還有一個低調但超實用的特性叫 Catalogs:讓整個 monorepo 的依賴版本集中在一個地方管理。
在 pnpm-workspace.yaml 宣告一次,各個 package.json 用 catalog: 去引用。要升級 Vite 只要改那一行,所有 package 一起到位。
pnpm-workspace.yaml — 版本只宣告一次
catalog:
next: 16.1.7
react: 19.2.6
typescript: ^6.0.3package.json — 用 catalog: 引用,不再各寫各的
{
"dependencies": {
"next": "catalog:",
"react": "catalog:"
},
"devDependencies": {
"typescript": "catalog:"
}
}更妙的是 named catalogs:把依賴照「用途」分組,build 工具一類、型別一類、自動化腳本一類。
於是 catalog:build 這個名字本身就在告訴你,這個套件為什麼存在。分類本身就是文件。
pnpm-workspace.yaml — 照用途分類
catalogs:
build:
typescript: ^6.0.3
tailwindcss: ^4.3.0
types:
"@types/react": 19.2.14
script:
puppeteer: ^24.43.1package.json — 名字自己會說話
{
"devDependencies": {
"typescript": "catalog:build",
"@types/react": "catalog:types",
"puppeteer": "catalog:script"
}
}差別就在最後這步。
"catalog:" 只告訴你版本被集中管理了。"catalog:build" 卻多說了一句「它是 build 工具、不進 production」,人看得懂、工具也看得懂,升級時風險評估都跟著變簡單。
這招 antfu 也專文推薦過,我自己的完整實踐寫在《Let Your Dependencies Explain Themselves》。
而 2026 年 4 月的 pnpm 11 又往前走了一步,把「安全」直接做成預設值:
- 新發布的套件要先隔離 24 小時才裝得進來
- 來路不明的子依賴預設直接擋掉
- store 換成 SQLite 之後安裝還更快

你的套件管理器,現在出廠就內建護欄了。
先把這個「24 小時隔離」記著,等一下講供應鏈攻擊的時候它會回來。
邊界是怎麼被「物理性」擋住的
pnpm 那個 symlink 設計,還順手做掉一件很多人沒注意到的事。
real capture — 我自己的 repo
$ ls -la node_modules | grep '^l'
lrwxr-xr-x vite-plus → .pnpm/vite-plus@0.2.2_…/node_modules/vite-plus
$ ls node_modules/.pnpm | head -3
@antfu+install-pkg@1.1.0
@babel+core@7.29.0
… ← store 裡只有一份真的,其餘全是 symlink只有你在 package.json 裡宣告過的套件,才會出現在 node_modules 的第一層。沒宣告的,你根本 import 不到。

邊界不是 lint 出來的,是被檔案系統擋住的。 幽靈依賴(phantom dependency)在這個結構下根本不可能發生。
這件事等一下第三波會再出現一次。因為 AI 最會犯的錯,就是繞過邊界。
CI 從「省」變成「守」,就是錯誤軸第一次真正被機器頂起來的徵兆。
至於它為什麼偏偏在這個時間點變成剛需?第三波才是答案。
第三波:AI 化,驗證變成戰場

產出已經解決了,然後呢?
前兩波合起來,是把「工具」這件事給解決掉了。我們現在手上有一套又快、又便宜、又整合的護欄機器。
但工具終究只是手段。護欄機器造好了,問題來了:這套護欄現在要拿去攔誰的錯?
回到最開頭那句伏筆:2023 年 Infra 攔的是人的錯。到了 2026 年,它要攔的是 AI 的錯。

而且把瓶頸推過去的,不是別的,就是 AI。
2026 年甚至冒出一個新領域來對付它,叫 harness engineering。核心論點就一句:
AI 失敗主要不是它推理不夠好,是環境太模糊,它不知道改這裡會不會弄壞那裡。
這不是換個名詞而已。因為 AI 的錯跟人的錯,性質真的差很多。
瓶頸落在哪:三種能力
這件事已經有人用另一套語言講得很清楚了。
工程師 Fortes Huang 有一篇談 AI 導入工程團隊的文章,把團隊的能力拆成三層:產出的能力、審查的能力、還有確認它到底對不對的能力。
Production
AI 導入後:快速暴衝Review
AI 導入後:壓力上升Validation
AI 導入後:成為新瓶頸他的觀察很簡單。AI 一進來,最上面那層產出瞬間暴衝,但下面兩層審查跟確認沒跟上。
於是瓶頸整個往下擠,卡在最後那層:驗證。

他還點出一個更狠的轉變:
責任的重心,正從「誰把 code 寫出來」,慢慢移到「誰能確認它是對的」。
人的錯 vs AI 的錯
那為什麼「驗證」偏偏在這個時間點卡住?因為要驗的東西,性質整個變了。
人的錯
攔了幾十年,攔得住AI 的錯
現在要攔的
量大 + 看起來都對 + 又不是你寫的。這三個加起來,人的肉眼 review 根本接不住。
AI 的錯長什麼樣
舉一個例子你大概就懂了。
你請 coding agent 加一個新頁面。它很聰明,看到專案別的地方有一段權限判斷,就複製了一份過來用。
然後 PR 編譯過、測試綠、畫面也對。你 review 的時候完全看不出問題,於是就合併了。
半年後產品要改權限規則。你改了原本那一處,卻忘了還有一份被複製出去的副本。那個新頁面,就這樣變成一個沒人記得的安全漏洞。
而最麻煩的地方是,這種漏洞不會有人來通知你啊。
這種錯還不只一種樣子:
- AI 很會把某條業務規則直接寫死在畫面元件裡,繞過你們原本集中管理的地方
- 或是為了讓功能快點跑起來,悄悄改掉既有的快取策略
這些單看每一個都很合理,合起來卻在慢慢啃食系統的一致性。
它們有個共同的結構特徵:同一條規則出現了兩個來源,或是規則被放到了不該放的位置。
這種特徵,人用肉眼 review 幾乎抓不到,但一條寫得夠好的 lint 規則反而攔得住。
就舉個最小的例子。如果你們的權限判斷本來就該只住在 lib/auth,那就寫一條規則,禁止其他地方去 import 內部的權限模組。AI 一想複製那段邏輯,CI 就先幫你擋下來了。
一條「權限只能有一個來源」的自訂規則
// 禁止 lib/auth 以外的檔案 import 內部權限實作
"no-restricted-imports": ["error", {
patterns: [
{
group: ["**/auth/internal/**"],
message: "權限判斷請一律走 lib/auth,不要自己複製一份",
},
],
}]規則本身不長,但它把「只有你們團隊才懂的規矩」變成了一條機器看得懂的護欄。人不用每次 review 都盯著這件事,AI 也繞不過去。
這裡剛好可以接回第二波那個伏筆。還記得 pnpm 用 symlink 讓沒宣告的依賴根本 import 不到嗎?那是物理性的邊界,由檔案系統執行。
這條 lint 規則則是邏輯性的邊界,由 CI 執行。
兩者是同一個念頭的兩種實作:與其事後靠人記得,不如讓它一開始就做不到。 對付 AI 尤其有效。它不會記得你們的規矩,但它繞不過機器。
模糊的邊界,人跟 AI 一起受害
還記得第一波埋的那個伏筆嗎?循環相依會讓 tree-shaking 失效。
那件事的傷害不只在打包:
| 症狀 | 後果 |
|---|---|
| 循環相依 | bundler 判斷不出有沒有被用到 → 全部保留 |
| chunk 變胖 | 下載與 parse 變慢 → LCP 惡化(畫面主內容更晚出現) |
| 同一個根因 | 同時傷害 bundle、效能,以及 AI 的判斷力 |

同一件事:結構模糊的時候,機器幫不上忙。 對 bundler 是這樣,對 AI 也是這樣。
把護欄鋪成一條路
唯一的解法,是讓自動化的護欄頂上去:那些 lint、型別檢查、測試、CI,通通變成攔截 AI 錯誤的關卡。
而且因為要攔的東西太多太雜,你不可能每個專案各自造一套。你得把整套護欄做成一個平台,讓每個開發者開箱就能用。
這個東西業界有個名字,叫 IDP(Internal Developer Platform)。
講白話就是把所有護欄鋪成一條路:你走在上面,該檢查的自動檢查、該擋的自動擋。不用自己架、也不用開單等平台團隊,你自己就能安全地把東西送出去。

而且這年頭規則還要寫成 AI 看得懂的格式:CLAUDE.md、AGENTS.md,等於是把你們團隊的規矩,翻譯給 AI 聽。
那驗證這一層具體要怎麼補?Fortes 給的方向裡有兩件事跟 infra 直接相關:
- 把 review 從「逐行看 code」改成「守系統邊界」:機器負責抓低階問題,人力集中判斷架構有沒有被打破
- 把高風險、容易回歸壞掉的流程交給測試基礎建設守門。而且 E2E 要用風險排序、不是用數量。多產一倍測試不等於信心多一倍,測到最貴、最怕壞的那條路徑才算數
這裡還有一個很容易被忽略的細節。
當那段 code 不是你寫的,護欄光會跳「過」或「不過」是不夠的。它得讓你看得見錯在哪、機器根據什麼規則判定、建議怎麼改,你才修得動、也才敢放手讓它擋。
所以這條鋪好的路不能是黑盒,它本身要是透明、可解釋的。
這不是空想。連 Oxc 的 Oxlint 都刻意把診斷結果做成 AI 讀得懂的結構化輸出:精確的錯誤位置、上下文、還附上對應的規則文件連結。
讓 AI 在寫 code 的當下就能把 linter 當護欄、邊寫邊修。工具鏈自己,已經在為「攔 AI」而改造了。
到這裡,三波就扣成一條鏈了。
還記得第一波那句嗎?結構乾淨機器才幫得上忙,就是這裡。因為 Rust 讓驗證變得夠便宜,我們才負擔得起一直驗證、大量驗證,也才接得住 AI 噴出來的那道洪水。
便宜讓跑滿變得可能,跑滿又讓我們接得住 AI。
三波扣成一條鏈
不只 AI:真實攻擊與法規
而且逼我們「驗證更多」的力量,還不只 AI。
2025 到 2026 年,JavaScript 生態被一隻叫 Shai-Hulud 的供應鏈蠕蟲掃過。光第一波就攻陷了 500+ 個套件,而且它會自我複製、一路往下游擴散。
差不多同一時間,歐盟通過了網路韌性法案 CRA,從外部要求軟體供應鏈必須可以被驗證。
生態的回應也已經出現。還記得上一段 pnpm 11 那個「新套件隔離 24 小時」嗎?它防的正是這種剛上架就有毒的攻擊。
套件管理器已經把供應鏈防禦做成預設值了。
security.yml:防禦當預設值
這種「防禦當預設值」長什麼樣?看個現場。
vite-plus 的 security.yml 只有十幾行,但藏了三道防線:
security.yml — 真實檔案,節錄
name: Security Analysis
on:
pull_request: # 每個 PR 都跑,不是每週跑
permissions: {} # 權限預設歸零
jobs:
security:
steps:
- uses: actions/checkout@9c091bb… # 用 commit SHA 釘死,不用 tag
with:
repository: rolldown/rolldown # 連上游也一起稽核
- uses: oxc-project/security-action@2ac862d…三道防線分別是:
- 每個 PR 都跑供應鏈掃描,用 oxc 自家的 security-action
permissions: {}+ commit SHA 釘死,被劫持的 tag 碰不到你- 連鎖定版本的上游 Rolldown 都抓下來掃,同一把尺量供應商

這些防蠕蟲的姿勢全是預設值,不是出事後才補的。
內有 AI、外有真實攻擊跟法規,全指向同一個方向。
所以這其實不是一時的 AI 炒作,是結構性的轉變。
那不是紙上談兵,我自己就在做

講到這裡都還是趨勢跟觀念。你可能會想:講得很好,但真的有人這樣做嗎?
有,而且不只我。
接下來給你看兩個迴圈。第一個是官方的,vite-plus 每天晚上真實在跑的那個。第二個是我自己造的,同一個哲學、跑在我每天的工作裡。
官方的迴圈:upgrade-deps.yml
第二波拆過的那個 repo 裡,最讓我愣住的是一支叫 upgrade-deps 的 workflow。
它每天午夜做這些事:
- 自動把 npm 跟 cargo 的依賴全部升到最新
- 試著 build
- 壞掉就讓 Claude Code 去修
- 修完之後 build、test、snapshot 護欄全跑一遍
- 最後自動開一個 PR,給人看最後一眼
yaml 裡給 AI 的目標寫得很直白:
bring the project back to a fully green state

Claude 出場兩次,人出場一次
細看它怎麼用 AI 更有意思。
跑的是官方的 anthropics/claude-code-action,prompt 就直接寫在 yaml 裡。前面步驟的成敗結果會動態塞進 prompt 給 AI 當上下文,修復步驟一二三四列得清清楚楚。
甚至叫 agent 去讀 repo 裡的 .claude/agents/ 文件照規矩辦事。這不就是前面說的嗎?把你們團隊的規矩,翻譯給 AI 聽。
而且 Claude 在這條線上出場兩次:
- 第一次當修理工:把 build 修回綠燈
- 第二次當文書:讀
git diff幫這個 PR 寫 commit message 跟描述
順帶一提,它的發版鏈裡也有一個人工核可的關卡。連官方都是「高風險的地方,人看最後一眼」。

「AI 負責生產、護欄負責接住」這件事,不是我腦補的未來。官方 repo 每天都在這樣過日子。
我的迴圈:後端驅動的 code-gen
第二個是我自己最得意的,跟官方那個迴圈同一個形狀。他們每晚修依賴,我在後端每次改動時同步 API 型別。
先講那個大家應該都很痛的場景。
後端改了 API,前端就得跟著改。一個欄位動了,前端的型別、介面、呼叫的地方全都要手動對。又重複、又無聊、又超容易漏,而且常常是上線了才發現對不上。
我的做法是把這件事整條自動化:
- CI 每次都盯著後端的
openapi.yaml - 一有變動就用 Hey API 的
@hey-api/openapi-ts重新產生 TypeScript 型別 - 自動發一個 code-gen MR 到前端 repo
- MR 裡還會讓 AI 先分析這次後端的改動、前端有哪些地方要跟著調,直接補進同一個 MR

後端驅動的 code-gen pipeline
這條 pipeline 剛好同時打中今天兩條軸:
- 把型別自動生出來 = 消滅重複
- 確保前端有正確跟著改到 = 攔錯誤
我先講重複那半,再回頭講錯誤那半。
重複那半:確定性的產出
為什麼挑 Hey API?因為它的輸出是確定性的:同一份 spec 進去,每次出來的 code 都一樣。
所以前端的型別永遠跟後端是同一個來源。沒人手抄、也不會兩邊各寫一份慢慢漂掉。
光這一步,就把「對型別」這件重複勞動整個收掉了。
錯誤那半:撐住它的是型別鏈
關鍵在前端的架構。
如果那個 interface 很複雜,我不會讓畫面元件直接去用生成出來的型別,而是在前端 repo 疊一層 UI model。元件只認這層 model,整個前端只有 model 這一個地方碰生成的原始型別。
ui-model/user.ts — 整個前端唯一 import 生成型別的地方
import type { UserDTO } from "@/api/__generated__"; // codegen 產物,raw
// 畫面只認這個乾淨的 model
export interface UserVM {
id: string;
name: string;
isActive: boolean;
}
export function toUserVM(dto: UserDTO): UserVM {
return {
id: dto.uuid,
name: dto.full_name ?? dto.email,
isActive: dto.status === "ACTIVE",
};
}後端 Spec
openapi.yaml生成層
@hey-api/openapi-tsUI Model
adapter元件層
React Components為什麼要多疊這一層?因為這樣才能把 TypeScript 的優勢整個榨出來。
因為依賴變得乾淨又單向,openapi.yaml 一改,型別錯誤就會沿著這條鏈自己冒出來:
raw 一動 → UI model 先紅 → 用到那個欄位的元件跟著紅。
TS 會把每個受影響的點都幫你標出來,想漏改都難。

投影片上那兩句手寫註記是重點:沒有任何元件碰得到 raw,而 UI model 是唯一的那道門,由一條 lint 規則守著。
這剛好就是我第一波埋的那句話,在這裡真的發生了:結構越乾淨、機器越幫得上忙。依賴夠乾淨、夠單向,TS 這台機器才追得到底。
這條型別鏈只有在「大家真的都走 UI model」的時候才成立。
只要有人圖方便繞過去、直接 import 生成型別,保證就破了。
所以我會再加一條 lint 規則守住這個邊界,禁止 model 以外的地方 import raw,跟第三波那條「權限只能有一個來源」是同一招。
另外 type check 一定要是 CI 擋 merge 的關卡,不然自動發的 MR 只會變成一堆沒人理的紅點。這就是第二波「CI 從省變守」在撐著。
不過型別鏈能保證的只有「結構」對不對。
萬一後端把一個欄位型別沒變、但語意偷偷換了,TS 就不會紅了。
這種改動還是得靠後半那段:讓 AI 去判斷前端邏輯要怎麼跟,外面再包測試跟 pipeline 當護欄。
這也剛好呼應第三波那句:AI 失敗常常是因為環境太模糊,而我這層乾淨的結構,等於先幫 AI 把環境理乾淨了。
所以這個案例把兩條軸一次收齊了:
- codegen 把重複收掉 = 消滅重複
- 型別鏈 + AI + 護欄 = 攔錯誤,而且攔的是 AI 自己的錯

就一句話:AI 負責生產,我做的 infra 負責接住它。 這句話已經活生生跑在我自己的工作裡了。
那你現在能做什麼
講了三波趨勢,最後我想給還在寫 feature 的你,幾個明天就能動手的起點。不用一次到位。
先換掉格式化
把格式化從 Prettier 換成 Oxfmt,它幾乎零成本、又幾乎完全相容,先讓團隊實際感受一次「快到你根本不在意它跑了幾遍」。
把痛點寫成規則
把你們團隊踩過最痛的那個「只有你們才懂的錯」,寫成一條 lint 規則,這正是通用工具永遠攔不到、但 AI 幾乎一定會犯的那種錯。
讓 CI 從「省」變「守」
重新看你的 CI,如果它還在為了省時間而跳過檢查,試著反過來,全部都跑、靠快取加速,把它從一個省錢工具,變成一片沒有缺口的護欄。
重新看待護欄
最後一步不用寫任何 code,就是換一個角度看那些擋你的檢查,它們不是來找你麻煩的,它們是你敢把一半的 code 交給 AI 的唯一理由。
回到那張地圖
繞了一圈,其實就一張地圖、一句話。
那張地圖是兩條座標軸:重複,跟錯誤。
重複那條幾十年沒變,也是你本來就懂的。真正在反轉的是錯誤那條,從攔人的錯,變成攔 AI 的錯。
而 Rust 化、統一化、AI 化這三波,講到底只是同一條反轉,在不同層次上的展開而已。
不只是我的分類,數據也這樣說
如果你覺得這只是我一個人在腦補分類,State of JS 2025 的數據給了一點佐證:
- Rust 底層的 Rolldown 一年內從 1% 用量跳到 10%
- 受訪者寫出的 code 有將近 29% 是 AI 生成的,比前一年多了快一半

Rust 化跟 AI 化這兩波,數據上都真的在發生。

上圖是 State of JS 2025 把 Rolldown 選為年度亮點的那段。
留三句話給你帶回家
所以如果你是剛入行、平常專心寫 feature 的朋友,我想留三句話給你。
第一,別焦慮。 你本來就懂的那一半,也就是自動化重複,沒有變。
第二,看懂方向。 真正在翻轉的只有錯誤的來源,從人變成 AI。
第三,也是最重要的,重新理解護欄。
在 AI 時代,那些 lint、測試、CI 不是來擋你麻煩的。它們是讓你敢相信「AI 幫你寫的那半段 code」的唯一理由。
你能放心讓 AI 幫你加速,正是因為背後有這條鋪好的路,接得住它的錯。

寫得快不是交付快,能安全地確認它是對的,才是交付快。
一句話收掉
這是我整場 talk 的最後一張。你只要記得這句就夠了。

回到那兩樁收購
去年 JSDC 那場的結尾,我放了一句「The Foundation Defines the Height」,地基決定高度。
當時講的是 monorepo 的地基。現在整個前端的地基都在洗牌,這篇算是把那句話重新丈量了一次。

回到開頭那兩樁收購。
平台級的公司花錢搶前端工具鏈,不是因為打包器本身多值錢,而是因為在 AI 時代,誰掌握了「驗證」,誰就掌握了下一個十年的地基。
這兩樁收購剛好各站一邊:
- Cloudflare 拿下 VoidZero,把整條「驗證的工具鏈」收進自己的部署平台
- Anthropic 買 Bun 更直接,Claude Code 本身就是打包成 Bun 執行的。AI 要讓 agent 大量產出、又要快速跑起來自我驗證,自然會想掌握那個又快又全能的 runtime
Bun 也在那場的未來展望裡。當時我最有感的是 Midjourney 的案例:百萬名使用者的產品只靠五個人維護,整套工具都跑在 Bun 上。
他們的哲學是「Oppose bloat in infrastructure」,基礎設施越精簡,做大膽的決定就越輕鬆。
現在回頭看 Anthropic 的選擇,就是同一個邏輯的放大版。

而站在這張新地圖上,我能做的,就是站在 AI 後面,把那條接得住它的路,一段一段往前鋪。
收尾
以上就是我在 v-taiwan 的分享內容!
感謝 v-taiwan 主辦方給我這個機會,也感謝現場所有來聽的朋友。如果你對前端 infra、工具鏈或是 AI 時代的驗證有任何想法,歡迎透過網站上的聯絡方式找我聊聊。