前端系統設計:從團隊怎麼分工,推到畫面怎麼渲染

文字解析 · 1 支影片 · 產生於 2026-10-01 00:54

🎧 語音解析📝 筆記✍️ 練習

🎧 語音解析 56m28s · TTS 講解與作者原聲交錯;點章節可跳。
邊聽邊看逐句講稿,點任一句從那裡開始
章節(18)

1. Outline

  1. 起點 · Frontend System Design Explained w/ Senior Engineer (Microfrontends, Monorepo, MCP UI, Reactjs)
    以「AI 讓實作變快、驗證變慢」為樞紐,把前端系統設計串成一條連續推理:先用 Conway's law 把團隊拆成垂直切片(微前端 + 微服務),再逐一償還切分欠下的債(gateway、BFF、負載平衡、容器、CDN、design system、MCP、monorepo),最後轉向體感層(Core Web Vitals、code splitting、渲染策略、SSE)。

2. YouTuber 的思維推導

Frontend System Design Explained w/ Senior Engineer (Microfrontends, Monorepo, MCP UI, Reactjs)

theSeniorDev · 38m02s · 字幕 en · vision=on (這是一支全程對著白板/架構圖講解的影片,transcript 裡「looking at our client-server model」「a typical microservice blueprint will look like something like this」「as you see there, it can even render a map」等指示語遠超過三次,圖本身承載了推理的主要結構,所以 vision 開啟。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 2s
segment 1m46s 5m10s
shot 1m21s 9s
analyze 16m15s 19m10s
render 5s –

作者的推導有一條很清楚的主軸:**先問誰在工作,再問系統長什麼樣,最後才問畫面怎麼畫。**

他從一個時代前提起手——AI 已經會寫前端 code,所以「會實作」不再稀缺。但他沒有停在這個老生常談上,而是丟出一個更精準的觀察:coding agent 把實作時間壓到接近零,卻**推高了驗證時間**。這句話是整支影片的樞紐:既然瓶頸從「寫」搬到了「確認寫對了沒」,那麼好的架構就不再是「優雅」或「可擴展」,而是**讓每一次變更都容易被驗證**。之後每一個技術選擇,他都會回到這個標準上重新評價一次。

有了標準,他開始拆。第一刀從人下手:團隊四十個人、stand-up 開一個半小時,這種結構從開發角度就無法 scale。Conway's law 提供了機制——想要小而獨立的團隊,就得有小而獨立的系統切片。於是後端拆成 microservices,前端拆成 microfrontends 加一個 shell,兩邊對接成 **vertical slice**:一個團隊完整擁有的縱向路徑。這是全片的結構高點,也是他職涯建議的來源——要成為能吃下整條切片的人。

接下來的每一段,其實都是在**還切分欠下的債**。切開了,跨網路請求的雜事重複了 → API gateway 把 edge functions 收成一次。gateway 沒解決資料形狀與擁有權 → BFF 讓前端團隊自己擁有後端。每一層都是單機 → load balancing。技術棧太雜、部署變噩夢 → Docker 與 orchestration。機房離使用者太遠 → CDN。團隊各自出貨、畫面開始不一樣 → design system。design system 躺在程式庫裡沒接上 AI → design-to-code MCP。程式碼散在上千個 repo、agent 看不見全貌 → monorepo。這一長串看似鬆散的名詞,其實是同一筆帳的九期分期付款。

在傳統議題收尾之後,他插入 **MCP UI** 作為前沿:當 LLM 不只回文字而是回 UI 元件,前端要怎麼接。然後才轉向最後一個維度——**體感**。這裡他換了一套語言:Core Web Vitals 把「好慢」拆成三個可歸因的數字,critical rendering path 說明數字為什麼難看,code splitting 處理「送太多 JavaScript」,渲染策略處理「畫面該在哪裡生成」,最後 server-sent events 補上請求—回應模型涵蓋不到的即時推送——而它的選擇理由,正好又回到他一貫的方法:**先看需求的形狀(LLM 的通訊是不對稱的),再選技術。**

把這條鏈拉直來看,他真正想教的其實不是二十個名詞,而是一種提問順序:這件事卡住了誰?成本落在哪一邊?有沒有一個切法能讓變更的爆炸半徑變小、讓驗證變快?學會這個順序,名詞會自己長出來。

推理鏈:每段留給下一段的線索

每一列是一段,箭頭後的字是這段留給下一段的線索。點段落標題跳到該段。

  1. 開場:為什麼前端要學系統設計 → 留下一個還沒回答的問題:既然要「拆」,那第一刀該從哪裡下?作者選擇不從前端開始,而是先回到後端的 microservices——因為要先看懂拆的動機。
  2. 從單體到微服務:團隊撐不住了 → 拆分的動機成立了,但還缺一個原則:憑什麼相信「組織」和「架構」會互相牽動?下一段作者用 Conway's law 補上這個環節,同時揭露 AI 帶來的真正瓶頸。
  3. AI 的真正瓶頸:verification time → 後端切好了、組織也對齊了,但前端仍是一整塊——這個不對稱就是下一段的起點。
  4. 前端還是單體:微前端與 shell → 前端切開了、shell 也就位了,但切開的微前端要怎麼跟切開的微服務對上?下一段用 vertical slice 把兩邊接起來。
  5. 垂直切片、職涯兩極與 blast radius → 切片之間要靠網路溝通,而每個請求都得處理認證、快取、限流這些重複的雜事——這個新增的成本就是下一段要解決的問題。
  6. API Gateway:把 edge functions 收成一次 → 留下一個 gateway 解不掉的缺口:它把橫切關注點收攏了,卻沒有改變資料的形狀,client 仍要對一堆長相不同的 API 各打各的;更麻煩的是,前端要一個新欄位還是得去別的團隊 backlog 排隊。
  7. BFF:前端團隊自己擁有後端 → 架構越接越長:client → gateway → BFF → 微服務。但這條鏈上的每一台 server 都是單機,使用者一多就撐不住——這個規模問題留給下一段。
  8. Load balancing:單台 server 的天花板 → 要開出很多個一模一樣的 instance,就得先能把應用程式打包成「到哪台機器都跑得起來」的東西——這正是下一段 Docker 要解的問題。
  9. 容器化:Docker 與 orchestration → 部署與擴展都自動化了,但無論開幾台機器,資料仍然要從機房飛到使用者面前——這段物理距離是下一段要處理的問題。
  10. CDN:跟光速借時間 → 效能與部署都處理完了,接下來要回頭面對切分留下的另一筆帳:各自獨立的團隊,做出來的畫面正在慢慢長得不一樣。
  11. Design system:對抗視覺分歧 → design system 有了,但它還躺在程式庫裡等人手動使用;下一段要把它接進 AI 的工作流,讓 agent 直接讀得到設計本身。
  12. Design-to-code MCP 與 Atomic CSS → 設計、元件、AI 工作流都接上了,但這些微前端與 design system 還散在各自的 repo 裡,agent 一次只看得到其中一個——這個 context 的邊界問題留給下一段。
  13. Monorepo:給 agent 看得見邊界 → 到這裡傳統的前端系統設計已經完整了;下一段作者轉向一個全新的東西——當 LLM 不只回文字、而是直接回 UI 元件時,前端架構要怎麼接。
  14. MCP UI:讓 LLM 回你元件而不只是字 → 不管介面怎麼變,畫面終究要被畫出來、而且要夠快——下一段回到效能,處理「快不快」到底怎麼量。
  15. Core Web Vitals 與關鍵渲染路徑 → 既然 LCP 的頭號兇手是「送了太多 JavaScript」,那下一步自然是問:能不能只送這一頁真正需要的那些?
  16. Code splitting 與 lazy loading → JavaScript 送得剛剛好了,但如果第一個畫面本身就得等 JavaScript 跑完才出現呢?下一段回到更根本的問題:畫面到底該在哪裡被渲染。
  17. 渲染策略:CSR、SSG、ISR、SSR → 畫面渲染的問題解決了,但還有一類資料不遵守「請求—回應」的節奏:伺服器要主動、持續地推東西過來。這是最後一段的主題。
  18. 即時通訊:polling、WebSocket、SSE

3. 逐段說明

Frontend System Design Explained w/ Senior Engineer (Microfrontends, Monorepo, MCP UI, Reactjs)

1. 開場:為什麼前端要學系統設計 0:00–0:46

作者開門見山:AI 越來越會寫前端 code,前端工程師唯一保持競爭力的路是把系統設計與架構能力拉上來。他指出坊間系統設計內容幾乎都偏後端、完全忽略前端。接著預告整支影片的大綱:從微前端架構、BFF 之類的系統設計模式,到 monorepo 與 server-side rendering 等渲染策略,最後談怎麼用 AI 與 agentic coding 把這些系統送上 production。

承上 從『前情提要』裡的那個現實出發:AI 已經很會寫前端 code,而市面上的系統設計教材幾乎都在講後端。這兩件事加起來,就是這支影片存在的理由。

推理因為作者認定「會寫元件」這件事的稀缺性正在被 AI 吃掉,所以他把前端工程師的價值重新定位在「決定系統長什麼樣」上,並直接宣告接下來要補的是那塊被忽略的前端系統設計。他把大綱先攤開——微前端、系統設計模式、monorepo、渲染策略、AI 部署——等於預告整支影片是一條由「團隊怎麼分工」推到「畫面怎麼渲染」的連續推理,而不是零散的名詞列表。

AI 補充作者沒說破的是這條論證的隱含前提:AI 取代的是**局部、可驗證的實作**,取代不了**跨模組的取捨**。寫一個按鈕元件有標準答案,決定「這個按鈕該屬於哪個微前端、狀態放哪裡、誰能改它」沒有。整支影片其實都在放大這個縫隙。另外要先建立一個閱讀姿勢:他接下來講的每個概念(gateway、BFF、CDN、SSR)在後端教材裡都存在,差別是他一律從**前端團隊的處境**去問「這對我有什麼用」,這也是把它當前端系統設計來讀的方式。

system design

系統設計

決定一個系統由哪些元件組成、彼此怎麼溝通、怎麼擴展與部署的設計活動。

一般人聽到 system design 會直接想到後端的 QPS、分片、快取,但它本質上是「在限制下做取捨」。前端的限制是網路延遲、瀏覽器單執行緒、使用者裝置差異與團隊人數,取捨對象是 bundle 大小、渲染時機、狀態放哪裡。作者整支影片就是在建立一套前端專屬的取捨語彙。

相關術語: microfrontends (包含的模式之一)

出處:第 1 段「開場:為什麼前端要學系統設計」

agentic coding

代理式編程

讓 AI coding agent 自主規劃、修改、執行、驗證程式碼的開發方式,而不只是補全單行。

和 autocomplete 型的 AI 輔助最大的差別在「誰持有迴圈」。autocomplete 由人一步步驅動,agentic coding 是你交出一個目標,agent 自己讀檔、改檔、跑測試、再改。這讓實作速度飆升,但也把瓶頸從「寫」搬到「確認它寫對了沒」——這個轉移是這支影片後面所有架構建議的根源。

相關術語: verification time (造成)

出處:第 1 段「開場:為什麼前端要學系統設計」

留給下一段 留下一個還沒回答的問題:既然要「拆」,那第一刀該從哪裡下?作者選擇不從前端開始,而是先回到後端的 microservices——因為要先看懂拆的動機。

2. 從單體到微服務:團隊撐不住了 0:46–2:32

要談微前端得先從後端的 microservices 說起。作者用 client-server 模型:一開始 server 與 client 都是單體,功能一直加,團隊也一直長大——他遇過 40 人的開發團隊,光每天 stand-up 每人講一分半就開一個半小時。這種架構從「開發」的角度就不可能 scale。他搬出 Jeff Bezos 的 two pizzas team(5–9 人),並補一刀:有了 AI 之後,two pizza team 變成 one pizza team。

client-server 單體模型的圖:後面所有拆解都從這張圖長出來,看了才知道「原點」長什麼樣
1:08 · client-server 單體模型的圖:後面所有拆解都從這張圖長出來,看了才知道「原點」長什麼樣
承上 承接上一段留下的問題「第一刀從哪裡下」:作者的答案是先回後端,因為 microservices 的拆分動機比微前端更容易看清楚。

推理因為上一段把問題定位在「系統怎麼設計」,所以作者接著要證明拆分的驅動力**不是技術,是人**。他刻意從最小的 client-server 單體圖起手,然後只加一個變數——團隊人數——就讓這張圖失效:40 個人、每天一個半小時的 stand-up。這一步很關鍵,因為它把「要不要用微服務」從架構品味的問題,改寫成組織成本的問題。two pizzas team 是他給的量化上限,而「AI 讓 two pizza 變成 one pizza」則把這個上限再往下壓,順勢把 AI 拉進論證裡。

AI 補充這裡值得補一個作者跳過的因果:團隊變大帶來的成本不是線性的。n 個人之間的溝通路徑是 n(n-1)/2 條,40 人就是 780 條——這才是 stand-up 開一個半小時的數學原因,也是為什麼「再加一個人」通常讓專案更慢(Brooks 定律)。另外要注意他的論證方向:他**不是**說微服務讓系統更快或更省資源(多半相反,你會多付網路延遲與運維成本),他說的是微服務讓**團隊**能平行前進。這個區分後面每次談到取捨時都會回來。

術語:monolithclient-server model

monolith

單體架構

整個應用程式的所有功能都在同一份 code base、同一個部署單位裡。

monolith 本身不是壞事,它是所有系統合理的起點:部署簡單、沒有網路邊界、重構容易。它變成問題只在一個條件下——很多人要同時改它。所以「該不該拆」的正確問法不是「我們的系統夠大嗎」,而是「有多少人在同一份程式碼上互相卡住」。

相關術語: microservices (拆解後成為)

出處:第 2 段「從單體到微服務:團隊撐不住了」

microservices

微服務

把後端拆成多個各自擁有 API、資料庫與部署流程的小型服務。

每個微服務對外只露 API,內部的語言、資料庫、發布節奏都可以不同,團隊之間只透過 API 溝通。代價很具體:你把「函式呼叫」換成了「網路呼叫」,於是要處理逾時、重試、資料一致性與分散式追蹤。作者在這支影片裡只取它「讓團隊獨立」的那一面,運維成本那一面沒展開。

相關術語: monolith (對照組)、microfrontends (前端的對應)

出處:第 2 段「從單體到微服務:團隊撐不住了」

client-server model

主從模型

客戶端發出請求、伺服器回應的基本網路架構模型。

這是整支影片反覆重畫的那張底圖:左邊 client、右邊 server、中間兩條箭頭。作者每介紹一個新概念,幾乎都是在這張圖上多加一個盒子(gateway、BFF、load balancer、CDN、edge location)。把這張圖記在腦裡,後面所有架構都變成「這個盒子插在哪一段線上」。

相關術語: monolith (初始形態)

出處:第 2 段「從單體到微服務:團隊撐不住了」

two pizzas team

兩個披薩團隊

Amazon 的團隊規模原則:一個團隊小到用兩個披薩就餵得飽(約 5–9 人)。

這條規則的重點不在人數本身,而在「溝通路徑」與「一個團隊能不能獨立擁有一個服務」。Amazon 用它來強制服務邊界與組織邊界對齊。作者把它接到 AI 上,主張 agent 讓同樣產出所需的人更少,所以理想團隊還會再縮小。

相關術語: microservices (對應的組織單位)

出處:第 2 段「從單體到微服務:團隊撐不住了」

見仁見智 1:45
「as many as you can feed with one pizza」
作者剛說完這條規則叫 two pizzas team,緊接著卻把它描述成「一個披薩餵得飽」。Amazon 的原始規則是**兩個**披薩餵得飽的人數(約 5–9 人),一個披薩會把上限壓得比他自己給的 5–9 人還低,前後矛盾。他下一句「有了 AI 就變成 one pizza team」才是刻意的引申。
依據: Jeff Bezos 的 two-pizza team rule,Amazon 內部沿用至今的說法為 two pizzas
留給下一段 拆分的動機成立了,但還缺一個原則:憑什麼相信「組織」和「架構」會互相牽動?下一段作者用 Conway's law 補上這個環節,同時揭露 AI 帶來的真正瓶頸。

3. AI 的真正瓶頸:verification time 2:32–4:31

作者丟出這支影片最關鍵的原則:像 Claude Code 這種 coding agent 把「實作時間」壓到接近零,但它們**拉高了驗證時間(verification time)**。所以 AI 時代的前端工程師,任務是設計出「降低驗證時間、抑制架構漂移、同時放大開發速度」的系統——重點不再是寫得快,而是系統要極度容易驗證。接著用 Conway's law 導出結論:想要小而獨立的團隊,就得把系統切成小而獨立的垂直切片,而這件事從後端拆出 microservices 開始。

feature team 與 platform team 的組織圖,對照 Conway's law:組織長什麼樣,架構就長什麼樣
2:52 · feature team 與 platform team 的組織圖,對照 Conway's law:組織長什麼樣,架構就長什麼樣
microservice 藍圖(API → business logic → persistence → DB),這是後面所有架構的最小組成單位
3:48 · microservice 藍圖(API → business logic → persistence → DB),這是後面所有架構的最小組成單位
承上 接住上一段留下的環節:既然拆分的動機來自團隊,作者用 Conway's law 把「組織」與「架構」正式綁在一起,並先插入一個會影響後面所有決策的前提——AI 改變了瓶頸的位置。

推理因為上一段已經證明「人多就卡住」,所以作者這一段要回答「那 AI 讓一切變快之後呢」。他給的答案是這支影片最反直覺的一句:coding agent 把**實作時間**壓到接近零,卻**推高了驗證時間**。這一步把 AI 從「加速器」重新定義成「產能轉移器」——產出變多,於是審查、測試、確認正確性的負擔變成新的瓶頸。有了這個前提,他才敢下結論:AI 時代的架構目標是**讓系統容易被驗證**。接著 Conway's law 提供機制:想要小而獨立的團隊,就得有小而獨立的垂直切片;而切片要從後端的 microservices 開始長。

AI 補充「verification time」值得停下來想,因為它決定了你後面每個架構選擇的方向。同一段 code,放在一個 20 萬行、全域狀態亂竄的單體裡,你要確認它沒壞掉得跑完整套回歸測試;放在一個邊界清楚、只有 3,000 行的微前端裡,你讀 diff 就知道影響範圍。作者的主張其實是:**架構決定 diff 的可讀性,而 diff 的可讀性決定你敢不敢用 AI 產出的東西**。另外補一個他略過的方向性——Conway's law 原本是描述性的(架構「會」長得像組織),實務上常被反過來用成規範性的 inverse Conway maneuver:先把團隊照你想要的架構切好,架構自己會長成那個樣子。作者說的「想要小團隊就得切系統」正是這個反向用法。

術語:feature teamplatform team

verification time

驗證時間

確認一段程式碼真的正確、沒有破壞既有行為所需的時間。

相對於 implementation time(實作時間)。AI 讓後者趨近於零,於是前者成為新的瓶頸——這是整支影片的軸心命題。降低驗證時間的手段幾乎都是架構層級的:小的部署單位、清楚的模組邊界、可獨立跑的測試、型別與設計系統帶來的約束。看完這支影片後,你可以拿這個指標去評價任何架構提案:它讓我更容易確認我沒改壞東西嗎?

相關術語: agentic coding (因它而浮現)、blast radius (正相關)

出處:第 3 段「AI 的真正瓶頸:verification time」

architectural drift

架構漂移

系統實際的樣子隨著時間偏離原本設計的意圖。

漂移不是一次大崩壞,是一千次小妥協:這裡繞過一層抽象、那裡多一個直接呼叫。AI 會加速漂移,因為它產出快、而且每次只看得到局部 context,很樂意複製一個相近的既有寫法而不是沿用正確的抽象。作者後面提出的 design system 與 monorepo,都是在給 agent 一個「正確答案就在附近」的環境。

相關術語: verification time (一起惡化)

出處:第 3 段「AI 的真正瓶頸:verification time」

Conway's law

康威定律

系統的架構會長得像設計它的組織的溝通結構。

Melvin Conway 在 1967 年提出的觀察。它常被引用來解釋「為什麼我們的系統這麼難改」——因為組織就是那樣切的。實務上更有用的是它的反向操作(inverse Conway maneuver):與其硬改架構,不如先改團隊邊界,讓架構自己長過去。作者這一整段其實就是在做這件事。

相關術語: vertical slice (導出)

出處:第 3 段「AI 的真正瓶頸:verification time」

feature team

功能團隊

擁有某個產品功能端到端全部技術層的跨職能團隊。

相對於依技術分層的 component team(前端團隊、後端團隊、DBA 團隊)。分層團隊的每個需求都要跨三個團隊排程,功能團隊則一個團隊吃下整條路徑。代價是每個團隊都得具備全端能力,這也是作者一直勸前端工程師往全端走的原因。

相關術語: platform team (互補角色)、vertical slice (擁有)

出處:第 3 段「AI 的真正瓶頸:verification time」

platform team

平台團隊

負責共用基礎設施與工具(CI/CD、design system、前端工具鏈)的團隊。

它的產品是「其他團隊的開發體驗」,客戶是內部工程師。判斷一個平台團隊健不健康的標準是:功能團隊是**自願**使用它的東西,還是被規定使用。前者代表它真的降低了摩擦,後者通常代表它變成了新的瓶頸。

相關術語: feature team (服務對象)、design system (常見產出)

出處:第 3 段「AI 的真正瓶頸:verification time」

留給下一段 後端切好了、組織也對齊了,但前端仍是一整塊——這個不對稱就是下一段的起點。

4. 前端還是單體:微前端與 shell 4:31–6:16

後端拆完了,前端還是一整塊。作者點出前端單體的痛:太多人往同一個 client 推 code,一個人改到全域 CSS 就影響所有人,溝通成本高到無法 scale。解法是把前端單體切成多個可獨立部署的前端應用,再用一個 **micro frontend shell** 把它們兜起來。shell 負責全域功能——auth、routing、語言、global state——其他微前端都被 shell 載入,並由 shell 把全域狀態傳下去。他舉例:header 可以獨立跑在 header.theseniordev.com。

shell 與其下各微前端的階層圖,說明 auth/routing/語言等全域狀態怎麼往下傳
5:35 · shell 與其下各微前端的階層圖,說明 auth/routing/語言等全域狀態怎麼往下傳
各微前端可獨立部署在自己網域(header.theseniordev.com)的示意,說明「獨立部署」具體長什麼樣
6:02 · 各微前端可獨立部署在自己網域(header.theseniordev.com)的示意,說明「獨立部署」具體長什麼樣
承上 承接上一段揭露的不對稱:後端已經切成微服務、組織也對齊了,前端卻還是一整塊,於是整條鏈的瓶頸原封不動地移到前端身上。

推理因為上一段證明了拆分的價值,所以作者這一段要說明「同樣的刀怎麼砍在前端」。他先把前端單體的痛講具體——太多人推同一個 client,一條全域 CSS 規則就能波及所有人——這是刻意的,因為前端的耦合比後端更隱蔽:後端至少有 API 當邊界,前端共用的是同一個 DOM、同一份 CSS、同一個 bundle。接著他導出微前端,並立刻補上關鍵零件:**shell**。這一步很重要,因為切開之後必須有人管全域的東西(auth、routing、語言、global state),shell 就是那個「不能被拆掉的中心」。最後用 header.theseniordev.com 這個例子把「獨立部署」講成一個具體的網域。

AI 補充作者省略了微前端最現實的三個代價,但它們決定你該不該用:**一、bundle 重複**——每個微前端各自帶 React,使用者可能下載三份,要靠 Module Federation 之類的機制共享依賴。**二、版本偏移**——shell 傳下去的 global state 形狀一改,所有微前端都得跟著改,這其實是一個沒有型別檢查的分散式 API。**三、樣式洩漏**——他說的「改一條全域 CSS 影響所有人」在微前端裡並不會自動消失,除非你做了 CSS 隔離。所以微前端的正確判準和微服務一樣:**你有幾個團隊在互相卡住**。團隊只有一個卻上微前端,你買到全部的成本、沒有任何好處。另外「shell 管 auth 和 routing」意味著 shell 是單點故障,它掛了整個站就掛了——這也是為什麼 shell 通常做得極薄。

術語:independent deployability

microfrontends

微前端

把前端單體拆成多個可獨立開發、獨立部署的前端應用,再於執行時組合起來。

組合的時機有三種:build time(當成 npm 套件裝進來,最簡單但失去獨立部署)、run time(瀏覽器動態載入,最常見,Module Federation 屬於此類)、server side(在伺服器把 HTML 拼起來,SEO 最好)。作者講的是 run time 這種。要記住它是**組織問題的解法**,不是效能解法——它幾乎一定讓效能變差一點。

相關術語: microservices (後端的對應)、micro frontend shell (由它組合)

出處:第 4 段「前端還是單體:微前端與 shell」

micro frontend shell

微前端外殼

負責載入各微前端並掌管 auth、routing、語言、全域狀態等跨切片功能的容器應用。

也常叫 container、host 或 app shell。設計原則是**盡量薄**:它每多管一件事,所有微前端就多一條共用的耦合線,而且它是單點故障。實務上 shell 通常只做三件事——決定載入誰、提供身分、提供路由——其餘全部下放。

相關術語: microfrontends (組合)、global state (持有)

出處:第 4 段「前端還是單體:微前端與 shell」

global state

全域狀態

跨越多個應用或元件、所有人都讀得到的共享狀態,例如登入身分與語系。

在微前端裡,global state 是 shell 對所有微前端的隱性 API。它沒有型別檢查、沒有版本號,卻被所有人依賴——所以它是微前端裡最容易腐爛的地方。務實的做法是把它壓到最小(身分、語系、主題),其餘狀態各切片自理。

相關術語: micro frontend shell (由它下放)

出處:第 4 段「前端還是單體:微前端與 shell」

independent deployability

獨立部署能力

一個模組可以不等待其他模組、單獨發布上線的能力。

這是微服務與微前端唯一真正的賣點,其他好處都是它的衍生。判斷標準很殘酷:如果你上線 A 之前必須先協調 B 一起上,那你只是把單體切成了分散式單體(distributed monolith)——付了網路的代價,卻沒買到獨立性。

相關術語: microfrontends (目的)

出處:第 4 段「前端還是單體:微前端與 shell」

留給下一段 前端切開了、shell 也就位了,但切開的微前端要怎麼跟切開的微服務對上?下一段用 vertical slice 把兩邊接起來。

5. 垂直切片、職涯兩極與 blast radius 6:16–8:31

微前端配上微服務,就得到 **vertical slice**:一個微前端對上同領域的一到多個微服務,由一個獨立團隊擁有、獨立發布。作者由此推到職涯建議:前端工程師會往兩極走——往 full-stack 的 feature team,或往 infra/design system 團隊;並主張要盡快變成「vertically integrated engineer」,一個能跨全端、配 coding agent 的一人團隊。最後回到 AI:微前端與微服務**縮小了 production bug 的 blast radius**,PR 更小、context 更少,AI 工具因此更有效率,驗證時間也跟著降低。

vertical slice 圖:微前端 + 微服務被一條線圈成一個團隊的所有物,是全片的核心結構
6:32 · vertical slice 圖:微前端 + 微服務被一條線圈成一個團隊的所有物,是全片的核心結構
前端職涯往兩極分化的示意圖,對照自己現在站在哪一邊
7:25 · 前端職涯往兩極分化的示意圖,對照自己現在站在哪一邊
承上 接住上一段留下的接合問題:微前端已經切好、shell 也能組合它們,現在要把它跟後端的微服務對上,形成一個團隊能完整擁有的單位。

推理因為前後端各自都切開了,所以作者這一段把兩條線收在一起:一個微前端 + 同領域的一到多個微服務 = 一個 **vertical slice**,由一個團隊獨立擁有、獨立發布。這是全片的結構高點——前面所有拆分都是為了得到這個單位。收完之後他做兩件事:一是把架構結論翻譯成職涯建議(往 full-stack 的功能團隊走,或往 infra/design system 走,並主張成為 vertically integrated engineer);二是回到 AI,指出小切片降低 **blast radius**、縮小 PR、減少 context,所以 AI 工具更有效率、驗證時間更短。這一步完成了第 3 段開出的支票:架構確實可以拿驗證時間當設計目標。

AI 補充要小心「垂直整合」這個建議的邊界。作者的論證是「AI 補上你缺的那一半技能,所以一個人能吃下整條切片」,這在 CRUD 型功能上成立;但在需要深度的地方(資料庫查詢計畫、分散式一致性、複雜的無障礙互動)AI 給的是**看起來對**的答案,而你缺乏判斷它對不對的能力——這正好又回到 verification time:你驗證不了的領域,AI 幫不了你。所以比較安全的讀法是:**廣度用來知道要問什麼、跟誰對接;深度仍然要自己選一到兩個方向長。**另外 blast radius 這個詞值得記住,因為它給了「小 PR」一個實質理由——不是「小比較好看」,而是**出事時壞掉的東西比較少、找起來比較快**。

術語:cognitive load

vertical slice

垂直切片

一個功能從前端到後端到資料庫的完整縱向路徑,由單一團隊擁有。

相對於 horizontal layer(水平分層:前端層、後端層、資料層各自成隊)。分層的問題在於每個需求都要橫跨三個團隊的 backlog;垂直切片把整條路徑收進一個團隊,代價是每個團隊都要有全端能力。這也是 feature team(見第 3 段)在架構上的投影。

相關術語: feature team (由它擁有)、microfrontends (組成部件)

出處:第 5 段「垂直切片、職涯兩極與 blast radius」

blast radius

爆炸半徑

一次變更或一個故障實際能波及的範圍。

從資安與 SRE 借來的詞。它把「模組化」這個抽象好處變成可以估算的東西:如果付款微前端掛了,商品頁還活著嗎?如果活著,你的 blast radius 就被限制住了。在 AI 大量產出程式碼的情境下這特別重要,因為出錯的頻率必然上升,你唯一能控制的是**每次出錯的代價**。

相關術語: verification time (正相關)、microfrontends (被它縮小)

出處:第 5 段「垂直切片、職涯兩極與 blast radius」

cognitive load

認知負荷

理解一段程式碼或做出一個變更所需要同時記在腦中的資訊量。

近年架構討論(例如《Team Topologies》)把它當成劃分團隊邊界的第一原則:一個團隊能承擔的認知負荷有上限,超過就會出現漏接與品質下滑。有趣的是這個限制對 AI 也成立——context window 就是 agent 的認知負荷上限,所以「人看得懂的邊界」和「agent 做得好的邊界」高度重疊。

相關術語: blast radius (一起下降)

出處:第 5 段「垂直切片、職涯兩極與 blast radius」

vertically integrated engineer

垂直整合工程師

能配合 coding agent 獨立吃下整條垂直切片的工程師。

作者自創的說法,本質是「AI 時代的 full-stack」。務實的讀法是 T 型能力:橫向覆蓋整條切片好讓你不必等別人,縱向在一到兩個領域有真正的深度好讓你驗證得了 AI 的產出。只有橫向而沒有縱向的人,在 AI 面前最沒有議價能力。

相關術語: vertical slice (能獨立擁有)

出處:第 5 段「垂直切片、職涯兩極與 blast radius」

留給下一段 切片之間要靠網路溝通,而每個請求都得處理認證、快取、限流這些重複的雜事——這個新增的成本就是下一段要解決的問題。

6. API Gateway:把 edge functions 收成一次 8:31–10:15

微前端要打很多後端服務,每個請求都帶著所謂的 **edge functions**:caching、HTTPS、authentication、content negotiation、rate limiting。每接一個微服務就兩邊各實作一次,overhead 極大。解法是 API gateway:client 只實作一次 edge functions,請求進 gateway 後再轉發給後端服務,後端只管自己的邏輯。這些服務都住在 virtual private cloud 裡,唯一入口就是 gateway,所以安全。額外好處是效能:client↔gateway 走 HTTPS,gateway↔微服務可以走 HTTP,省掉 handshake 的來回。

API gateway 擋在 VPC 前面的拓樸圖,HTTPS 與 HTTP 分界就畫在這張圖上
9:22 · API gateway 擋在 VPC 前面的拓樸圖,HTTPS 與 HTTP 分界就畫在這張圖上
承上 接住上一段留下的新成本:切片之間全靠網路溝通,於是每個請求都要重複處理認證、快取、限流這些跟業務無關的雜事。

推理因為切分帶來了大量跨網路的請求,所以作者這一段先把「重複的部分」命名為 **edge functions**——caching、HTTPS、authentication、content negotiation、rate limiting——再指出問題:每接一個微服務,前後端就各實作一次,成本隨服務數量線性膨脹。命名完問題,解法就自然浮現:把這些橫切關注點抽到一個**單一入口**,也就是 API gateway。他接著補兩個好處來完成論證:安全上,後端全部躲進 VPC,唯一的門就是 gateway;效能上,對外 HTTPS、對內 HTTP,省掉 handshake 的來回。

AI 補充gateway 的真正價值是「橫切關注點只實作一次」,但這也意味著它是**單點故障與單點瓶頸**:所有流量都經過它,它掛了整站就掛了,它慢了整站就慢了。所以實務上 gateway 一定是多實例 + 前面再擺負載平衡(下一段的主題)。另外要提醒一個和作者論證方向不同的現實:對內走純 HTTP 這件事,在近年的 zero trust 思路裡已經不被推薦——「進了 VPC 就是安全的」預設一旦被攻破(例如某個服務被入侵),內網流量就完全裸奔。現代做法是 mTLS 或 service mesh 自動加密,把 TLS 的成本交給基礎設施吸收。他的說法在 2015 年是主流,現在是 debatable。

API gateway

API 閘道

擋在所有後端服務前面的單一入口,集中處理認證、限流、快取等橫切關注點。

它是 Facade 模式在網路層的實作。要留意它和下一個要講的 BFF 的差別:gateway 是**每個系統一個**、對所有 client 一視同仁;BFF 是**每種 client 一個**、為那種 client 量身裁切。兩者常常同時存在——gateway 在外層擋安全,BFF 在內層裁資料。

相關術語: edge functions (集中實作)、backend for frontend (常被混淆)

出處:第 6 段「API Gateway:把 edge functions 收成一次」

edge functions

邊緣功能

每個 API 請求都需要、但與業務邏輯無關的共通處理:快取、TLS、認證、限流、內容協商。

它們是典型的 cross-cutting concerns(橫切關注點):分散實作會到處重複,集中實作會產生瓶頸。gateway 選擇了後者,並用水平擴展來抵銷瓶頸。注意「edge」這個詞在不同脈絡意思不同——這裡指「系統的入口」,CDN 那一段的 edge location 指「地理上的邊緣」。

相關術語: API gateway (被它承接)

出處:第 6 段「API Gateway:把 edge functions 收成一次」

virtual private cloud

虛擬私有雲

雲端上邏輯隔離的私有網路區段,內部資源預設不對公網開放。

VPC 給你網路層的隔離:只有你明確開的那扇門(通常就是 gateway 或 load balancer)能從外面進來。它讓後端服務可以不必各自處理公網安全問題,但別把它當成唯一防線——一旦有服務被攻陷,攻擊者就在牆內了,這正是 zero trust 主張「內網也要驗證」的原因。

相關術語: API gateway (唯一入口)

出處:第 6 段「API Gateway:把 edge functions 收成一次」

rate limiting

限流

限制單位時間內單一來源可發出的請求數,避免濫用與過載。

常見演算法是 token bucket(允許短時間突發)與 sliding window(更平滑但較耗資源)。放在 gateway 是為了在請求打到任何業務邏輯之前就擋掉,成本最低。前端工程師該知道的對應面是:拿到 429 時要用 exponential backoff 重試,而不是立刻重打。

相關術語: edge functions (其中一項)

出處:第 6 段「API Gateway:把 edge functions 收成一次」

見仁見智 9:55
「HTTPS it's likely less performant than the HTTP」
這個說法以今天的標準過度簡化了。TLS 1.3 把 handshake 壓到 1-RTT、session resumption 可到 0-RTT,開銷通常只有個位數毫秒;而且 HTTP/2 與 HTTP/3 在瀏覽器上都**只**在 TLS 之上啟用,所以走 HTTPS 反而拿得到多工與更好的壅塞控制,整體常常更快。內部服務間改走純 HTTP 現在也不再是推薦做法——zero trust 與 service mesh 的主流意見是內網一律 mTLS,把加密成本交給基礎設施。
依據: RFC 8446(TLS 1.3, 2018);主流瀏覽器僅在 TLS 上支援 HTTP/2 與 HTTP/3
留給下一段 留下一個 gateway 解不掉的缺口:它把橫切關注點收攏了,卻沒有改變資料的形狀,client 仍要對一堆長相不同的 API 各打各的;更麻煩的是,前端要一個新欄位還是得去別的團隊 backlog 排隊。

7. BFF:前端團隊自己擁有後端 10:15–13:46

有了 gateway,client 還是得對一堆長相不同的微服務 API 各打各的 fetch,而且只要功能需要一丁點後端改動,就得去求後端團隊排 backlog。作者說這是他們輔導的大公司工程師最大的痛。解法是 **backend for frontend(BFF)**:一個屬於前端團隊的後端,接住前端請求再轉給微服務,讓前端團隊能以 full-stack 的方式端到端擁有一個功能。再往前一步,每種 client(desktop / mobile)有各自的 BFF,避免 over-fetching 與 under-fetching。他強調這代表前端工程師必須懂 API design,也要懂一點 GraphQL。

BFF 夾在 client 與微服務之間的圖,可以直接對照上一張沒有 BFF 的版本
11:32 · BFF 夾在 client 與微服務之間的圖,可以直接對照上一張沒有 BFF 的版本
desktop BFF 與 mobile BFF 並排的圖,說明同一批微服務怎麼對外長出兩套 API
13:02 · desktop BFF 與 mobile BFF 並排的圖,說明同一批微服務怎麼對外長出兩套 API
承上 接住上一段留下的缺口:gateway 解決了「重複的雜事」,但沒解決「client 仍要對一堆長相不同的 API 各打各的」,也沒解決前端團隊得排隊等後端改欄位的組織問題。

推理因為 gateway 只是把橫切關注點收攏,並沒有改變資料的形狀與擁有權,所以作者這一段換一種刀法:不是再抽一層共用的,而是給前端團隊**一個自己的後端**。他先把痛點講到最痛——每個小欄位都要去別的團隊 backlog 排隊,這是他輔導的大公司工程師最常見的卡點——再導出 BFF:一層屬於前端團隊、負責聚合與裁切的後端。有了它,前端團隊就能以 full-stack 的方式端到端擁有一個功能。接著他把 BFF 推到第二層價值:**每種 client 一個 BFF**,desktop 與 mobile 各有各的 API,解決 over-fetching 與 under-fetching。最後他把結論落到能力清單上:前端工程師得懂 API design、懂一點 GraphQL。

AI 補充BFF 的判準其實是「**擁有權**」而不是「技術」。技術上你當然可以叫後端團隊多開一個聚合端點,但那條端點的排程仍然在他們手上——BFF 的價值是把那個決定權搬到前端團隊,所以它必須由前端團隊部署、由前端團隊 on-call。如果 BFF 最後還是後端團隊在維護,你只是多了一層網路跳躍。要注意的成本有兩個:BFF 是**真的後端**,它有部署、監控、on-call、資安責任;而且 client 種類一多,BFF 就會重複,於是又出現「要不要抽共用層」的老問題。GraphQL 常被拿來當 BFF 的實作,因為讓 client 自己宣告要什麼欄位,正好一次解掉 over/under-fetching——但代價是快取變難(不再是單純的 URL 快取)與查詢複雜度攻擊的防護。作者提到 GraphQL 但沒提這兩個坑。

backend for frontend

前端專用後端

由前端團隊擁有、專門服務某一種 client 的後端層,負責聚合與裁切後端資料。

Sam Newman 命名的模式。它與 API gateway 的分工是:gateway 每個系統一個、管安全與流量;BFF 每種 client 一個、管資料形狀與擁有權。判斷你真的需要 BFF 的訊號是「前端老是為了一個欄位卡在別人的 backlog」,而不是「我們的 API 很多」。

相關術語: API gateway (位於其後)、over-fetching (用來解決)

出處:第 7 段「BFF:前端團隊自己擁有後端」

over-fetching

過度抓取

API 回傳的資料遠多於這個畫面實際需要的量。

在行動網路上這直接換算成延遲與流量費:抓回 40 個欄位只用 3 個,多出來的位元組全都要傳輸與解析。它和 under-fetching 是同一個病的兩面——用單一 API 服務形狀不同的 client,必然在某一端不合身。

相關術語: under-fetching (相反)、backend for frontend (被它解決)

出處:第 7 段「BFF:前端團隊自己擁有後端」

under-fetching

抓取不足

單次 API 回傳的資料不足以組成畫面,必須再發多次請求。

典型症狀是 N+1 請求:先抓一份清單,再為清單裡每一項各發一次請求。在高延遲網路上這是災難,因為總時間是延遲乘以請求次數。BFF 或 GraphQL 讓聚合發生在伺服器端,把 N+1 收成一次往返。

相關術語: over-fetching (相反)

出處:第 7 段「BFF:前端團隊自己擁有後端」

GraphQL

GraphQL

由 client 在查詢中宣告需要哪些欄位的 API 查詢語言。

它天生解掉 over/under-fetching,因為形狀由呼叫端決定。代價是:HTTP 快取失效(所有查詢都打同一個 POST 端點)、需要防禦惡意的深層巢狀查詢、錯誤處理不再靠 HTTP 狀態碼。所以它適合欄位需求多變的 BFF,不適合單純、穩定、需要重度快取的公開 API。

相關術語: backend for frontend (常見實作)

出處:第 7 段「BFF:前端團隊自己擁有後端」

留給下一段 架構越接越長:client → gateway → BFF → 微服務。但這條鏈上的每一台 server 都是單機,使用者一多就撐不住——這個規模問題留給下一段。

8. Load balancing:單台 server 的天花板 13:46–15:00

回到 client-server 模型:使用者一多,單台 server 就撐不住。作者給了具體數字——一台調校良好的 Node.js server 大約能扛 2,000 到 10,000 個並發請求,超過就得換方法 scale。最簡單的做法是 load balancing:開多個一模一樣的 server instance,前面擺一個 application load balancer 分流。他務實地說前端工程師不必鑽太深,但最好能自己用 Nginx + Docker Compose 在本機兜一個出來,重點是「能推理得出來」。

load balancer 把流量分給多個相同 instance 的圖,是理解水平擴展最直接的一張
14:32 · load balancer 把流量分給多個相同 instance 的圖,是理解水平擴展最直接的一張
承上 接住上一段留下的規模問題:client → gateway → BFF → 微服務這條鏈上,每一台都是單機,使用者一多就會先撞到某一台的上限。

推理因為前面幾段一直在增加架構的層數,所以作者這一段回頭處理「每一層自己怎麼撐住流量」。他先給一個具體錨點——調校過的 Node.js server 大約 2,000 到 10,000 並發——再指出超過就得換做法。解法是水平擴展:開多個一模一樣的 instance,前面擺 application load balancer 分流。這裡他刻意收斂範圍,明說前端工程師不必鑽進分流演算法,但最好能用 Nginx + Docker Compose 在本機兜一個出來,理由是「重點是你能推理得出來」——這也順手把下一段的 Docker 埋了進來。

AI 補充水平擴展能成立有一個前提作者沒點破:**server 必須是無狀態的(stateless)**。如果登入 session 存在某台 server 的記憶體裡,使用者被分到另一台就等於登出了。所以真正的第一步不是加機器,而是把狀態外移到 Redis 或資料庫;做不到就只能退而求其次用 sticky session,但那會讓分流失衡、也讓那台機器不能隨便重啟。另外 2,000–10,000 這個數字要當數量級讀而不是規格:純轉發的 I/O 密集工作可以很高,一旦有 JSON 解析、模板渲染或加密這類 CPU 工作,Node 的單執行緒特性會讓數字掉一到兩個級距。真正該記住的是**形狀**:I/O 密集看連線數,CPU 密集看核心數。

load balancing

負載平衡

把進來的流量分配到多個伺服器實例上,以突破單機的處理上限。

常見策略:round robin(輪流,最簡單)、least connections(給最閒的,適合請求耗時不均)、IP hash(同一來源固定到同一台,用來做 sticky session)。前端工程師最該知道的衍生效應是:在多實例環境下,**任何存在單機記憶體裡的狀態都不可靠**。

相關術語: horizontal scaling (實作手段)、stateless (前提)

出處:第 8 段「Load balancing:單台 server 的天花板」

horizontal scaling

水平擴展

靠增加機器數量來提升處理能力,而非提升單機規格。

對照 vertical scaling(垂直擴展,換更大台的機器)。水平擴展理論上沒有上限、也天生具備容錯(掛一台還有其他台),但要求應用程式無狀態;垂直擴展改起來最省事,但有物理天花板,而且升級時通常要停機。

相關術語: load balancing (需要)

出處:第 8 段「Load balancing:單台 server 的天花板」

stateless

無狀態

伺服器不在自己的記憶體裡保存跨請求的使用者狀態,每個請求都自帶所需資訊。

這是水平擴展的入場券。做法是把 session 放進共享儲存(Redis)或直接用自帶簽章的 token(JWT)。作者沒有明說這個前提,但沒有它,加機器只會製造出「有時候登出、有時候正常」這種最難查的 bug。

相關術語: horizontal scaling (必要條件)

出處:第 8 段「Load balancing:單台 server 的天花板」

concurrent requests

並發請求

同一時間點伺服器正在處理、尚未回應完成的請求數量。

注意它和 RPS(每秒請求數)不是同一件事:並發數 ≈ RPS × 平均回應時間。所以把回應時間從 200ms 降到 50ms,等於在不加機器的情況下把並發承載量變成四倍——這也是為什麼效能優化常常比擴容便宜。

相關術語: load balancing (觸發條件)

出處:第 8 段「Load balancing:單台 server 的天花板」

見仁見智 14:05
「it can usually satisfy up to 2,000 to 10,000 concurrent requests」
這個區間只在「幾乎純 I/O、每個請求 CPU 工作極少」的前提下成立,作者沒有講出這個前提。一旦每個請求有 JSON 序列化、模板渲染、加密或任何同步運算,Node.js 的單執行緒事件迴圈會讓實際承載量掉到數百甚至更低。反過來說,純轉發的代理型工作可以遠高於一萬。當成數量級的直覺可以,當成容量規劃的依據不行——實際數字只能靠壓測得出。
依據: Node.js 單執行緒事件迴圈模型;承載量取決於每請求的 CPU 時間與 I/O 比例
留給下一段 要開出很多個一模一樣的 instance,就得先能把應用程式打包成「到哪台機器都跑得起來」的東西——這正是下一段 Docker 要解的問題。

9. 容器化:Docker 與 orchestration 15:00–17:31

架構被拆成一堆微前端與微服務之後,部署反而變成噩夢:Python 的微服務、Node.js 的微服務、Vue 或 Next.js 的前端,各有各的 pipeline。解法是用 Docker 標準化:Dockerfile 是打包的食譜,產出的 image 包含程式碼、runtime(例如 Node)與作業系統(通常是 Linux)。只要 host 跑得動 Docker 就跑得動這個 image,不必管 Node 版本或依賴。DevOps 再把這些 image 丟進 container orchestration system(Kubernetes、AWS 的 ECS)處理負載平衡、多實例、失敗自動重啟。作者明講:前端工程師不必會 Kubernetes,但要能說出它在架構裡的位置。

Docker image 的分層圖(app code / runtime / OS),是理解「為什麼換 host 也能跑」的關鍵畫面
16:07 · Docker image 的分層圖(app code / runtime / OS),是理解「為什麼換 host 也能跑」的關鍵畫面
container orchestration 的部署 pipeline 圖,說明 Kubernetes 到底在幫你做什麼
16:52 · container orchestration 的部署 pipeline 圖,說明 Kubernetes 到底在幫你做什麼
承上 接住上一段留下的前置條件:要開出很多個一模一樣的 instance,就得先有一個「到哪台機器都跑得起來」的打包格式。

推理因為前面已經把系統拆成一堆技術棧各異的微前端與微服務(Python、Node、Vue、Next.js),所以作者這一段要解的是**部署的異質性**。他的推理很直接:如果每個服務都要自己一套佈建流程,拆分省下的協作成本會被運維成本吃回去。Docker 的作用是**把差異封裝進 image**——Dockerfile 是食譜,image 裡裝著程式碼、runtime 與作業系統,於是對外只剩一個統一介面:跑起來、開這個 port。統一之後才有下一步:把一堆 image 丟進 container orchestration system,讓它處理多實例、失敗重啟與負載平衡——也就是上一段那些事,現在由 Kubernetes 自動化。最後他務實地劃線:前端工程師不必會 Kubernetes,但要能說出它在架構裡的位置。

AI 補充有一個常見誤解值得澄清:Docker image 裡的「作業系統」不是完整的 OS,而是**使用者空間的檔案與函式庫**——kernel 是跟宿主機共用的。這解釋了兩件事:為什麼容器啟動只要幾百毫秒(不必開機),以及為什麼 Linux 容器不能直接跑在 Windows kernel 上(要靠虛擬機墊一層)。對前端工程師最有實感的好處其實不在 production,而在**本機**:一句 docker compose up 就能起一組和 CI 一模一樣的環境,「在我機器上是好的」這句話從此失效。而回到全片的主軸——容器讓 orchestration 能自動把壞掉的實例換掉,這等於把「出錯後的復原」也自動化了,同樣是在壓低 verification time(見第 3 段)。

Docker

Docker

把應用程式連同執行環境打包成可攜式 image 的容器化技術。

它解決的是「環境差異」而不是「資源隔離效率」——後者是 Linux kernel 的 namespace 與 cgroup 在做的,Docker 只是把它們包成好用的介面。對前端最大的日常價值是本機開發環境與 CI 完全一致。

相關術語: Docker image (產出)、container orchestration (被它調度)

出處:第 9 段「容器化:Docker 與 orchestration」

Docker image

Docker 映像檔

包含應用程式碼、runtime 與作業系統使用者空間的唯讀打包產物。

image 是分層的,每層對應 Dockerfile 的一個指令,層之間可以共用與快取——所以把不常變的步驟(安裝依賴)放前面、常變的(複製原始碼)放後面,可以讓重建快上一個數量級。注意 image 裡沒有 kernel,它是跟宿主機共用的。

相關術語: Docker (由它建立)

出處:第 9 段「容器化:Docker 與 orchestration」

container orchestration

容器編排

自動化容器的部署、擴縮、健康檢查與故障復原的系統。

Kubernetes 是事實標準,AWS 的 ECS 是較簡單的替代品。它的核心模型是**宣告式**的:你描述「我要三個副本」,控制迴圈持續把現實拉向這個描述——掛一個就補一個。前端工程師會碰到它的地方通常是 readiness probe(決定何時開始導流量進來)與 rolling update(決定新舊版本怎麼交替)。

相關術語: Docker image (調度對象)、load balancing (內建)

出處:第 9 段「容器化:Docker 與 orchestration」

Kubernetes

Kubernetes

最主流的開源容器編排系統,以宣告式設定管理容器叢集。

常縮寫為 K8s。作者的建議很中肯:不必會操作,但要能在架構圖上指出它的位置,並看懂 job description 提到它時在期待什麼。實務上前端最常需要理解的是「為什麼我的服務被重啟了」——通常是 liveness probe 失敗或記憶體超出限制。

相關術語: container orchestration (一種實作)

出處:第 9 段「容器化:Docker 與 orchestration」

留給下一段 部署與擴展都自動化了,但無論開幾台機器,資料仍然要從機房飛到使用者面前——這段物理距離是下一段要處理的問題。

10. CDN:跟光速借時間 17:31–20:01

這是全片第一個純前端概念。作者用一個實體限制開場:美國使用者要拿歐洲 server 的 JS/CSS,資料得橫跨大西洋來回,而**資料最快只能跑到光速**,長距離下每個請求會多出大約 200–250 ms 的延遲,這是繞不過去的物理限制。解法是縮短距離:CDN 把靜態資源推到全球各地的 edge location,請求會被導到離你最近的那一個。他接著把 CDN 定義成一個分散式快取——拿到資源叫 cache hit,server 推新版叫 cache invalidation,並連到前端熟悉的 cache busting。結論:CDN 是最便宜、最快改善 web performance 的手段,現代 CDN 還順便幫你壓縮與設好 cache policy。

全球 edge location 分佈與請求導向的圖,把「縮短物理距離」這件事畫成可以看的東西
18:37 · 全球 edge location 分佈與請求導向的圖,把「縮短物理距離」這件事畫成可以看的東西
承上 接住上一段留下的物理問題:部署與擴展都自動化之後,剩下的瓶頸不在機房裡,而在機房與使用者之間的那段距離。

推理因為前面所有優化都發生在伺服器端,所以作者這一段刻意換一個維度:他從一個**不可談判的物理限制**出發——資料最快只能以光速前進,美國使用者拿歐洲的檔案,一個來回就是 200–250 ms,任何程式碼優化都動不了它。這個開場很有力,因為它把問題從「我們寫得夠不夠好」改成「距離太遠」,於是解法只剩一種形狀:**把檔案搬近一點**。CDN 就是這個形狀的實作——邊緣節點遍布全球,請求被導到最近的一個。導出解法後他再做一次概念收攏:CDN 本質上是分散式快取,於是 cache hit、cache invalidation 都能套上來,並接到前端熟悉的 cache busting。結尾給出實用的判斷:CDN 是投入產出比最高的效能手段。

AI 補充這段最值得補的是「為什麼快取失效是難題」。cache busting 的做法是在檔名裡塞內容雜湊(app.a3f9c2.js),內容一變檔名就變,於是**舊檔案永遠不必失效**——你只要讓 index.html 不被快取,其餘檔案全部設成一年不變。這個組合是現代前端部署的標準答案,而作者只提到名詞沒說機制。另外要修正一個對 CDN 常見的想像:邊緣節點通常不是「事先被推滿」,而是**第一個請求的人回源拉一份、之後的人才命中**(pull 模式)——所以每個地區的第一位使用者仍然要付完整的來回延遲。最後一個作者沒展開但很實際的點:現代 CDN 已經不只放靜態檔,它還能跑程式碼(edge functions/edge workers),這讓「在離使用者最近的地方做個人化」變得可能——快取與運算的界線正在往邊緣移動。

CDN

內容傳遞網路

把靜態資源複製到全球各地的邊緣節點,讓使用者從最近的節點取得檔案。

除了縮短距離,現代 CDN 還順手做壓縮(Brotli)、協定升級(HTTP/3)、圖片格式轉換與 DDoS 防護。它是效能投入產出比最高的一步,因為幾乎不必改程式碼。要注意它只對可快取的內容有效——個人化、需要登入的內容仍然得回源,除非你用邊緣運算處理。

相關術語: edge location (由它組成)、cache hit (成功狀態)

出處:第 10 段「CDN:跟光速借時間」

edge location

邊緣節點

CDN 在世界各地部署、實際存放快取內容的伺服器據點。

使用者被導到哪個節點通常由 anycast 或 DNS 的地理判斷決定。要注意「離我最近」是**網路拓樸上的近**而不是地圖上的近,兩者偶爾會不一致。這裡的 edge 指地理邊緣,和第 6 段 edge functions 的「系統入口」是不同意思。

相關術語: CDN (組成單位)

出處:第 10 段「CDN:跟光速借時間」

cache hit

快取命中

請求的內容在快取中找得到,直接回應而不必回源伺服器。

對應的 cache miss 會觸發回源。命中率是 CDN 最重要的健康指標,而拉低命中率最常見的原因是 URL 帶了會變動的查詢參數(例如追蹤碼),讓同一份內容被當成很多份分開快取。

相關術語: cache invalidation (相對操作)

出處:第 10 段「CDN:跟光速借時間」

cache invalidation

快取失效

讓快取中的舊內容不再被使用,以確保使用者拿到新版本。

Phil Karlton 那句名言說電腦科學只有兩件難事,其中之一就是它。難在你無法確知哪些節點還存著舊的、也無法保證清除立刻生效。現代前端的解法是**繞過它**:用內容雜湊檔名讓新版本有新網址,舊的自然沒人要,於是根本不需要失效。

相關術語: cache busting (實作手段)、cache hit (相對操作)

出處:第 10 段「CDN:跟光速借時間」

cache busting

快取破除

在檔名或查詢字串中加入雜湊或版本號,讓內容一變更就產生新的網址。

module bundler 自動做這件事:app.a3f9c2.js。搭配「HTML 不快取、帶雜湊的資源快取一年」這組設定,就得到既永遠拿到最新版、又幾乎全部命中快取的效果。這是目前前端部署的標準答案。

相關術語: cache invalidation (用來迴避)

出處:第 10 段「CDN:跟光速借時間」

見仁見智 19:58
「whenever the server pushes a new version, that's called cache invalidation」
這個定義把兩件事混在一起了。cache invalidation 指的是**讓既有的快取項目失效**(CDN 上叫 purge),是一個明確的清除動作;「server 推上新版本」本身並不會讓舊快取失效,除非你主動 purge,或是用下一句他提到的 cache busting 讓新版本有新的網址。實務上正是因為 invalidation 不可靠,現代前端才幾乎全面改用內容雜湊檔名來繞過它。
依據: CDN 供應商(Cloudflare、Fastly、CloudFront)皆將 invalidation/purge 定義為主動清除既有快取項目的操作
留給下一段 效能與部署都處理完了,接下來要回頭面對切分留下的另一筆帳:各自獨立的團隊,做出來的畫面正在慢慢長得不一樣。

11. Design system:對抗視覺分歧 20:01–22:16

微前端讓各功能團隊獨立發布,代價是 code repetition 與 **visual divergence**——產品頁的按鈕跟付款頁的按鈕長得不一樣,使用者會察覺這其實是好幾個前端。解法是 design system:先定義 design tokens(主色、border、字體家族),現代做法是在 shell 的全域 CSS 裡用 CSS custom properties 宣告,再餵給所有微前端;再往上建可重用元件,讓功能團隊組裝。好處除了視覺一致與不重複程式碼,還能集中處理 accessibility 與單元測試。他最後把它連回 AI:一個扎實的 design system 是「AI 產出一堆不一致的元件」與「AI 產出穩定可靠結果」之間的差別,他自己每個新專案的第一件事就是先萃取 design system 餵給 coding agent。

design tokens 與可重用元件被各微前端共用的圖,說明一致性是怎麼從一個地方擴散出去的
20:57 · design tokens 與可重用元件被各微前端共用的圖,說明一致性是怎麼從一個地方擴散出去的
承上 接住上一段收尾留下的那筆帳:各自獨立的功能團隊各自出貨,畫面正在慢慢長得不一樣。

推理因為第 5 段建立的垂直切片讓團隊互相解耦,所以這一段要處理解耦的**副作用**:沒有共用的約束,產品頁的按鈕和付款頁的按鈕就會不一樣,使用者會察覺這其實是好幾個前端拼起來的。作者把這個現象命名為 visual divergence,並指出它同時是產品問題(失去一致性)與技術問題(重複的程式碼)。解法分兩層推進:先是 **design tokens**——用 CSS custom properties 在 shell 的全域層宣告,往下餵給所有微前端;再往上是**可重用元件**,讓功能團隊直接組裝。這個順序有意義:token 是最低成本、最容易共用的一致性;元件是更強的約束但也更難維護。最後他把整段接回 AI:design system 是 agent 產出穩定與否的分水嶺,他自己每個新專案的第一件事就是先萃取 design system 再開始讓 agent 寫。

AI 補充「design system 讓 AI 產出穩定」這句話值得展開成機制,因為它是這段最有操作價值的部分:coding agent 每次都在一個有限的 context 裡工作,它不知道你的品牌色,於是會**發明**一個。當專案裡存在 --color-primary 和一個既有的 <Button>,agent 面對的就不再是開放式創作,而是「選用哪個既有元件」的選擇題——選擇題的錯誤率遠低於申論題,而且錯了你一眼就看得出來。這正好又回到第 3 段的 verification time:**約束越強,驗證越快**。另外提醒一個作者沒說的順序陷阱:design system 太早做會變成猜測(你還不知道需要哪些元件),太晚做則要付重寫的代價。實務上的折衷是**先只做 token**——顏色、間距、字體、圓角這幾組變數幾乎不會猜錯,而它們就能擋掉大部分的視覺分歧。

術語:DRY principle

design system

設計系統

一組共用的設計決策與可重用元件,用來讓多個團隊產出視覺與行為一致的介面。

它比 UI 元件庫大:包含 tokens、元件、使用規範、無障礙標準與文件。判斷它成不成功的標準是**採用率**——如果功能團隊寧可自己刻也不用它,通常是因為它的元件不夠彈性,或提交改動的流程太慢。

相關術語: design tokens (最底層)、visual divergence (用來解決)

出處:第 11 段「Design system:對抗視覺分歧」

visual divergence

視覺分歧

不同團隊各自實作的介面逐漸長得不一樣,失去產品的整體一致性。

它是團隊解耦的必然副作用:獨立性越高,趨異的力量越強。所以微前端與 design system 是一組配套——前者製造獨立,後者提供共用的約束。只做前者,使用者會感覺產品是拼湊的。

相關術語: design system (被它抑制)、microfrontends (副作用來源)

出處:第 11 段「Design system:對抗視覺分歧」

design tokens

設計語彙

把顏色、間距、字體、圓角等設計決策抽成具名變數,作為設計與程式的共同語言。

現代做法是 CSS custom properties,因為它們可以在執行時被覆寫——這讓主題切換(深色模式、白牌客製)變成改一組變數而不是改一堆元件。它是 design system 裡投入產出比最高的一層:成本最低、跨技術棧、而且對 AI 產出的約束效果立竿見影。

相關術語: design system (組成基礎)、CSS custom properties (實作方式)

出處:第 11 段「Design system:對抗視覺分歧」

CSS custom properties

CSS 自訂屬性

以 --name 宣告、用 var(--name) 取用的原生 CSS 變數。

和 Sass 變數的關鍵差別是它**存在於執行時**並且遵循 CSS 的層疊與繼承——所以可以用 JavaScript 改、可以在媒體查詢裡覆寫、可以只在某個子樹裡換一組值。這三個特性正是主題化與微前端間共享樣式的基礎。

相關術語: design tokens (承載)

出處:第 11 段「Design system:對抗視覺分歧」

DRY principle

不重複原則

同一份知識在系統中只應該有一個權威來源。

全名 Don't Repeat Yourself。要注意它講的是**知識**不是**字元**——兩段長得一樣但會因為不同理由而改變的程式碼,硬要合併反而製造耦合。design system 是這個原則在架構層級的正確應用:按鈕的樣子確實是同一份知識。

相關術語: design system (應用於)

出處:第 11 段「Design system:對抗視覺分歧」

留給下一段 design system 有了,但它還躺在程式庫裡等人手動使用;下一段要把它接進 AI 的工作流,讓 agent 直接讀得到設計本身。

12. Design-to-code MCP 與 Atomic CSS 22:16–23:45

有了 design system,下一步是把它接上 AI 工作流。作者的情境:設計師在 Figma 裡先建了 design system,你在 library 裡實作它,然後用 **Figma MCP server** 配 coding agent 快速把功能組裝進垂直切片——他說多數公司正往這個工作流走,前端工程師必須知道 MCP server 是什麼、怎麼用,甚至可能得自己接。接著補一段 CSS 架構:把 design tokens 配上 **Atomic CSS** 方法論,做成 `.border` 這種原子類別讓其他開發者直接用——而 Tailwind CSS 就是 Atomic CSS 這個架構風格的一種實作。

Figma → MCP server → coding agent 的流程圖,是這段唯一講不清楚但畫得清楚的部分
22:42 · Figma → MCP server → coding agent 的流程圖,是這段唯一講不清楚但畫得清楚的部分
承上 接住上一段留下的落差:design system 已經存在,但它躺在程式庫裡等人手動 import;作者要把它接進 AI 的工作流。

推理因為上一段證明了「約束讓 agent 產出穩定」,所以這一段要把約束的**來源**再往前推一步:與其讓工程師把 Figma 上的設計翻譯成程式碼、再讓 agent 讀程式碼,不如讓 agent 透過 **MCP server** 直接讀設計本身。他描述的流程是:設計師在 Figma 建 design system → 你在 library 實作它 → coding agent 透過 Figma MCP server 直接取用,快速把功能組裝進垂直切片。接著他給出能力要求:知道 MCP server 是什麼、會用、必要時自己接。最後補一段 CSS 架構把上一段的 token 收尾——用 Atomic CSS 把 token 變成原子類別,並點名 Tailwind CSS 就是 Atomic CSS 的一種實作。

AI 補充MCP 值得用一句話講清楚它為什麼重要:它是**工具接進 LLM 的統一介面**。在它之前,每個 AI 應用要接 Figma、接 GitHub、接資料庫,都得各寫一套整合;MCP 把「有哪些工具、每個工具吃什麼參數」標準化,於是同一個 server 可以被任何支援 MCP 的 agent 使用。這對前端的實際意義是:設計稿不再是一張要被人眼翻譯的圖,而是**可查詢的結構化資料**——agent 可以問「這個元件用了哪個 token」而不是猜像素。至於 Tailwind 那句定位很準但值得補完:Atomic CSS 的代價是 HTML 會塞滿類別、可讀性下降,收益是 CSS 檔案大小不隨專案成長(類別會重複使用)、而且刪掉元件不會留下沒人敢刪的孤兒樣式。它和 design system 不衝突——token 定義值,atomic class 提供用法,元件封裝組合。

MCP

模型上下文協定

讓 LLM 以統一格式連接外部工具與資料來源的開放協定。

全名 Model Context Protocol。它解決的是 N×M 問題:N 個 AI 應用要接 M 個工具,原本要寫 N×M 套整合,有了共同協定只需要各實作一次。對前端最直接的應用就是 design-to-code:把設計工具變成 agent 可以查詢的結構化資料源,而不是要人眼翻譯的圖片。

相關術語: MCP server (由它實作)、agentic coding (賦能)

出處:第 12 段「Design-to-code MCP 與 Atomic CSS」

MCP server

MCP 伺服器

依 MCP 協定對外提供工具與資源,讓 coding agent 能存取特定系統的服務。

它可以在本機跑(存取檔案系統、資料庫)也可以遠端跑(存取 SaaS)。作者的建議很實際:不只要會用現成的,還要能為自家的內部工具寫一個——因為真正卡住 agent 的往往是公司自己的系統,那沒有現成的 server。

相關術語: MCP (實作)、design system (可作為資料源)

出處:第 12 段「Design-to-code MCP 與 Atomic CSS」

Atomic CSS

原子化 CSS

每個類別只負責一個樣式屬性,靠組合多個類別來構成介面的 CSS 架構風格。

收益是 CSS 體積不隨專案線性成長(類別高度重複使用),而且刪除元件時不會留下沒人敢動的孤兒樣式。代價是 HTML 變得冗長、語意變弱。它跟 design system 是互補而非替代:token 定義值、atomic class 提供用法、元件封裝常見組合。

相關術語: Tailwind CSS (一種實作)、design tokens (消費)

出處:第 12 段「Design-to-code MCP 與 Atomic CSS」

Tailwind CSS

Tailwind CSS

以預先定義的原子化工具類別建構介面的 CSS 框架。

它把 Atomic CSS 加上一組經過設計的預設尺度(間距、字級、顏色階),所以你拿到的不只是機制、還有一套現成的 design tokens。搭配 build 階段的清除機制,最終產出的 CSS 只包含實際用到的類別。

相關術語: Atomic CSS (實作於)

出處:第 12 段「Design-to-code MCP 與 Atomic CSS」

留給下一段 設計、元件、AI 工作流都接上了,但這些微前端與 design system 還散在各自的 repo 裡,agent 一次只看得到其中一個——這個 context 的邊界問題留給下一段。

13. Monorepo:給 agent 看得見邊界 23:45–25:16

微前端散在上千個 GitHub repo 裡,會長出不同的 code style、不同依賴、不同品質標準——這就是 **architectural drift / code style drift**;開發者換團隊就得重學一次,標準化完全沒發揮。解法是 monorepo:一個大 repository 裝下所有小應用,工具鏈共用,`npm run build` 一次把所有應用各自建好。作者把它接回 AI:monorepo 給 coding agent「跨服務邊界修改所需的 context」——你在微前端裡發現一段可重用的邏輯,可以在同一個 session 裡把它抽成 design system 的元件;分成兩個 repo 就得想辦法把兩份 repo 都餵進去。結論:微前端 + 微服務 + monorepo 通常是跟 AI 合作最有效率的組合。

多 repo 散落 vs monorepo 收攏的對照圖,這一段的論證完全建立在這張對照上
24:27 · 多 repo 散落 vs monorepo 收攏的對照圖,這一段的論證完全建立在這張對照上
承上 接住上一段留下的 context 邊界問題:微前端與 design system 散在各自的 repo 裡,agent 一次只看得到其中一個。

推理因為第 4 段的切分讓每個微前端各有一個 repo,所以這一段要處理切分的第三筆帳(前兩筆是視覺分歧與工作流斷裂):**標準的分歧**。散在上千個 repo 裡,code style、依賴版本、品質標準會各自漂移,開發者換團隊得重學一次,標準化的好處完全沒兌現。解法是把所有小應用收進單一 repository,共用工具鏈,一次 build 全部。接著他做出這段最有價值的轉折——monorepo 不只對人有用,**它給 coding agent 跨服務邊界所需的 context**:你在微前端裡發現一段可重用的邏輯,可以在同一個 session 裡把它抽成 design system 的元件;分成兩個 repo 就得想辦法把兩份都餵進去。結論是把三件事疊起來:微前端 + 微服務 + monorepo 是跟 AI 合作最有效率的組合。

AI 補充這裡有個表面矛盾值得拆開:**單一 repo 和獨立部署會衝突嗎?** 不會,因為 repo 邊界和部署邊界是兩件事。monorepo 管的是原始碼放哪裡與工具鏈怎麼共用,獨立部署(第 4 段)管的是誰能單獨上線——Nx、Turborepo 這類工具正是靠依賴圖判斷「這次改動只影響 payments,所以只重建與部署 payments」。真正的成本在別的地方:**規模**(單一 repo 大到讓 git 操作與 CI 變慢,Meta 與 Google 得自己寫工具)與**擁有權**(所有人都能改所有東西,需要 CODEOWNERS 這類機制把邊界重新畫回來)。另外對 agent 的價值可以講得更準:context 不只是「檔案都在」,而是 agent 能沿著 import 路徑**追蹤真實的依賴關係**——它看得到誰用了這個元件,才敢改它。這是跨 repo 時 agent 最常出錯的地方:它以為自己在做局部修改,實際上動到了別人的介面。

術語:polyrepo

monorepo

單一儲存庫

把多個應用與套件放在同一個版本控制儲存庫裡統一管理。

它和「單體」是完全不同的兩件事:monorepo 講的是原始碼放哪裡,monolith 講的是部署成幾個單位——你完全可以在 monorepo 裡放一堆獨立部署的服務。優點是原子化的跨專案修改(一個 PR 同時改元件與所有呼叫端)與統一的工具鏈;代價是 repo 規模與擁有權管理。

相關術語: polyrepo (對照組)、architectural drift (用來抑制)

出處:第 13 段「Monorepo:給 agent 看得見邊界」

polyrepo

多儲存庫

每個應用或套件各自擁有獨立的版本控制儲存庫。

天然的邊界與權限隔離是它的優點,代價是跨 repo 的修改要拆成多個 PR 依序合併,而且版本組合會爆炸(A 的 1.2 版搭 B 的 3.4 版有沒有測過?)。這也是 AI agent 在多 repo 環境下最容易做出「局部正確、整體壞掉」修改的原因。

相關術語: monorepo (對照組)

出處:第 13 段「Monorepo:給 agent 看得見邊界」

code style drift

風格漂移

不同專案的程式風格、依賴版本與品質標準隨時間各自偏離。

它的成本不在美觀,而在**人員流動**:開發者換團隊時的重新學習成本,以及 code review 時無謂的風格爭論。統一的 linter 與 formatter 設定是最低成本的解法,而 monorepo 讓這組設定只需要存在一份。

相關術語: architectural drift (較輕微的形式)、monorepo (被它解決)

出處:第 13 段「Monorepo:給 agent 看得見邊界」

留給下一段 到這裡傳統的前端系統設計已經完整了;下一段作者轉向一個全新的東西——當 LLM 不只回文字、而是直接回 UI 元件時,前端架構要怎麼接。

14. MCP UI:讓 LLM 回你元件而不只是字 25:16–27:45

作者說這是他最興奮的東西:MCP UI 是傳統網站與 LLM 應用之間的黏著劑。在聊天應用裡,你送出 query,LLM 回答——但這次它可以用 **UI 元件**回答,直接把商品、地圖 render 在答案裡。他用自己找活動場地的親身經驗舉例:聊著聊著,介面開始 render 場地卡片、跟他要輸入、甚至畫出地圖。運作機制是:model harness 在 context 裡提供 tool registry 與各 MCP server,LLM 回傳文字答案外還附上「render 某個 div」的指令,前端解析後渲染。他反駁「有了 chat 就不需要 UI」的說法,主張未來是 LLM 與傳統 web 的混合。

聊天介面裡直接 render 出場地卡片與地圖的實例畫面,這是「MCP UI 到底長什麼樣」唯一的具體證據
26:12 · 聊天介面裡直接 render 出場地卡片與地圖的實例畫面,這是「MCP UI 到底長什麼樣」唯一的具體證據
model harness → tool registry → LLM 回傳 render 指令的流程圖,說明元件是怎麼被決定要畫出來的
26:52 · model harness → tool registry → LLM 回傳 render 指令的流程圖,說明元件是怎麼被決定要畫出來的
承上 接住上一段的收束:傳統的前端系統設計已經拼完整了,作者轉向他認為的下一個前沿——LLM 不只回文字,而是直接回 UI。

推理因為第 12 段已經把 MCP 建立成「LLM 連接外部工具的標準介面」,所以這一段可以直接把它推到介面層:如果 LLM 能呼叫工具,它為什麼不能**要求前端渲染一個元件**?作者把 MCP UI 定義成傳統網站與 LLM 應用之間的黏著劑,並用親身經驗當證據——他找活動場地時,聊天介面突然 render 出場地卡片、要他給回饋、還畫出地圖。有了具體畫面他才拆機制:model harness 在 context 裡提供 tool registry 與各 MCP server,LLM 回傳文字答案外附帶「渲染某個 div」的指令,前端解析後渲染。最後他反駁「有了 chat 就不需要 UI」——他的論證是 UI 在傳達結構化資訊上仍然不可取代,未來是兩者的混合。

AI 補充這段最需要補的是**安全邊界**,因為作者完全沒提,而這正是把它從 demo 做成產品的分水嶺:讓 LLM 的輸出決定畫面上渲染什麼,等於把一個不可信的來源接到渲染路徑上。所以實作一定要走「**宣告式白名單**」而非「執行任意標記」——前端事先註冊好一組元件與各自的 props schema,LLM 只能回傳「元件名 + 通過驗證的參數」,絕不能回傳 HTML 或程式碼片段。這也是為什麼 MCP UI 的規格傾向用 iframe 或 sandbox 隔離第三方渲染。第二個作者略過的難題是**狀態歸屬**:使用者在 LLM 渲染出來的卡片上按了「Love it」,這個狀態算誰的?它得回到對話的 context 裡讓模型知道,又得反映在應用程式自己的資料上——這種雙寫是這類介面最容易出錯的地方。回到全片主軸看,MCP UI 其實是第 5 段那個 vertical slice 的延伸:一條新的垂直路徑,只是入口從網址列換成了對話框。

MCP UI

MCP UI

讓 LLM 在回應中指定要渲染的 UI 元件、由前端解析並呈現的擴充模式。

它把 LLM 的輸出從純文字擴到結構化的介面指令。安全的實作方式是前端註冊一組允許的元件與 props schema,LLM 只能引用名稱與通過驗證的參數,絕不執行 LLM 產生的標記或程式碼。目前規格仍在演進,屬於早期採用階段。

相關術語: MCP (建立於)、tool registry (依賴)

出處:第 14 段「MCP UI:讓 LLM 回你元件而不只是字」

model harness

模型外框

負責組裝 context、管理工具呼叫與回應迴圈的執行層。

它是包在模型外面的那層程式:決定把哪些訊息、哪些工具定義、哪些檢索結果放進 context,收到工具呼叫時實際去執行,再把結果送回模型。Claude Code 這類 coding agent 本身就是一個 harness。

相關術語: tool registry (提供)、agentic coding (執行基礎)

出處:第 14 段「MCP UI:讓 LLM 回你元件而不只是字」

tool registry

工具註冊表

提供給模型的可用工具清單,含名稱、用途說明與參數格式。

模型是靠這些**自然語言描述**來決定要不要呼叫、怎麼呼叫的,所以描述寫得好不好直接決定 agent 的表現——這是一種新的介面設計工作。工具太多也會反效果:清單塞滿 context 又讓模型難以選擇。

相關術語: MCP server (由它提供)、model harness (被它組裝)

出處:第 14 段「MCP UI:讓 LLM 回你元件而不只是字」

留給下一段 不管介面怎麼變,畫面終究要被畫出來、而且要夠快——下一段回到效能,處理「快不快」到底怎麼量。

15. Core Web Vitals 與關鍵渲染路徑 27:45–30:30

作者說這是前端職缺描述裡最常出現的效能模式。Core Web Vitals 是三個指標,量的是網站效能的三個面向:載入速度、互動速度、視覺穩定性,對應 **LCP**(按下 enter 到最大元素被畫出來)、**INP**(互動後多久重繪)、**CLS**(載入過程中畫面位移多少)。LCP 與 CLS 關於初次渲染,INP 關於重新渲染——這在元件框架下特別重要。要理解這些就得懂 critical rendering path:DOM → CSSOM → render tree → layout tree → paint operations → GPU → composite,再加上元件框架拿到資料後的 re-render,最後才畫出 LCP。結論很直接:JS 太多、CSS 太多、資料抓太多、server 太慢,LCP 就會很難看。

三個維度對應三個指標的對照表,是記住 Core Web Vitals 最有效的一張
28:12 · 三個維度對應三個指標的對照表,是記住 Core Web Vitals 最有效的一張
critical rendering path 的完整流程圖,LCP 為什麼慢的答案全在這條路徑上
29:12 · critical rendering path 的完整流程圖,LCP 為什麼慢的答案全在這條路徑上
承上 接住上一段的收尾:不管介面長什麼樣,畫面終究要被畫出來而且要夠快,所以先要有一套量「快不快」的語言。

推理因為前面十四段講的都是**結構**,所以作者從這裡開始轉向**體感**,而第一步必須是量測——否則優化只能靠感覺。他的推進方式很乾淨:先把「效能」拆成三個維度(載入速度、互動速度、視覺穩定性),每個維度配一個 Google 定義的指標(LCP、INP、CLS),於是模糊的「網站好慢」變成三個可以分別歸因的數字。接著他做關鍵的分組:LCP 與 CLS 屬於**初次渲染**,INP 屬於**重新渲染**——這個分組直接對應到元件框架的行為,也預告了後面兩段的分工。最後他把指標往下接到 critical rendering path:DOM → CSSOM → render tree → layout → paint → composite,說明 LCP 為什麼慢的原因全都藏在這條路徑的某一步上。

AI 補充這三個指標各自的**主因**值得記牢,因為它決定你要去改哪裡。**LCP** 幾乎總是卡在四件事之一:伺服器回應太慢(TTFB)、阻塞渲染的資源(同步的 CSS/JS)、最大元素本身載得慢(沒優化的主視覺圖)、或客戶端渲染要等資料。**CLS** 的頭號兇手是沒給尺寸的圖片與延遲載入的字體——解法便宜到近乎免費:img 標上 width/height、字體用 font-display: optional 或先配好 fallback 的尺寸。**INP** 則是主執行緒被長工作佔住,React 的常見版本是一次狀態更新引發整棵子樹重繪。另外補一個作者略過的重要區分:這些指標有**實驗室數據**(Lighthouse,在你的機器上模擬)和**真實使用者數據**(field data / CrUV,真實使用者的裝置與網路)兩種來源,兩者經常對不上——而 Google 排名採用的是後者。優化時盯錯數據源是很常見的浪費。

術語:reconciliation

Core Web Vitals

核心網頁指標

Google 定義的三個量化網站使用者體驗的指標:LCP、INP、CLS。

它們同時是搜尋排名訊號,所以兼具工程與商業意義。要分清兩種資料來源:Lighthouse 給的是實驗室模擬值,Search Console 用的是真實使用者的 field data,後者才影響排名。2024 年 INP 正式取代了原本的 FID。

相關術語: LCP (包含)、critical rendering path (由它決定)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

LCP

最大內容繪製

從導覽開始到視窗內最大的內容元素被渲染出來所經過的時間。

良好門檻是 2.5 秒。它是「使用者覺得這頁開好了沒」最接近的代理指標。常見兇手依序是:伺服器回應慢、阻塞渲染的資源、主視覺圖片太大、以及客戶端渲染要等資料回來。

相關術語: Core Web Vitals (其中之一)、code splitting (被它改善)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

INP

互動到下次繪製

從使用者互動到瀏覽器實際畫出回應之間的延遲,取整個瀏覽期間的代表值。

良好門檻是 200 毫秒。2024 年 3 月正式取代 FID,因為 FID 只量第一次互動的**等待**時間,量不到處理與繪製。在元件框架裡它幾乎等於「一次狀態更新引發的重繪有多貴」。

相關術語: Core Web Vitals (其中之一)、reconciliation (主要成本)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

CLS

累積版面位移

頁面載入過程中非預期的版面位移量的累積分數。

良好門檻是 0.1。最常見的兇手是沒有標尺寸的圖片、後到的字體、以及在既有內容上方插入的橫幅。它的修法是全部指標裡最便宜的——預留空間就好。

相關術語: Core Web Vitals (其中之一)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

critical rendering path

關鍵渲染路徑

瀏覽器從收到 HTML 到把畫面畫上螢幕之間必經的一系列步驟。

DOM → CSSOM → render tree → layout → paint → composite。理解它的實用價值在於知道**哪些操作只觸發最後一步**:transform 與 opacity 的變化可以只做 composite(交給 GPU、不重排不重繪),而改 width 或 top 會一路回到 layout。這就是動畫該用 transform 的原因。

相關術語: LCP (決定)、reconciliation (之前發生)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

reconciliation

協調

元件框架比對新舊虛擬樹、算出實際需要更動哪些 DOM 節點的過程。

它是 INP 的主要成本來源。React 的做法是比較 virtual DOM 樹並批次套用差異,Vue 3 靠編譯期分析縮小比對範圍,Svelte 則乾脆在編譯期產生直接的 DOM 操作、完全不做執行時比對。知道這個差異,你才看得懂各框架的效能主張在爭什麼。

相關術語: INP (主要成本)、critical rendering path (觸發)

出處:第 15 段「Core Web Vitals 與關鍵渲染路徑」

留給下一段 既然 LCP 的頭號兇手是「送了太多 JavaScript」,那下一步自然是問:能不能只送這一頁真正需要的那些?

16. Code splitting 與 lazy loading 30:30–32:00

接續效能:傳統 module bundler 把所有 JavaScript 打成一個大檔,載入它會直接毀掉 Core Web Vitals。**Code splitting** 讓你只把某一頁真正需要的 JavaScript 送過去——最簡單的切法是按 route,`/login` 只拿登入要用的元件,圖表很重的 dashboard 就不會一起送。這由 Webpack 或 Vite 這類 module bundler 配合 router 動態載入完成。作者把它升到更高的心智模型:**lazy loading**(用到才載)是 eager loading(一進來全載)的反面,可以綁在捲動、換頁或點擊上,一切都是為了讓 Core Web Vitals 更好。

單一大 bundle 被按 route 切開的圖,說明「只送需要的 JavaScript」到底切在哪裡
30:57 · 單一大 bundle 被按 route 切開的圖,說明「只送需要的 JavaScript」到底切在哪裡
承上 接住上一段留下的線索:既然 LCP 的頭號兇手是送了太多 JavaScript,那就要問能不能只送這一頁真正需要的那些。

推理因為上一段已經把「JS 太多 → LCP 難看」建立成因果,所以這一段直接處理那個因。作者先指出傳統 module bundler 的預設行為——全部打成一個大檔——正是問題本身;接著給出最小可行的切法:**按 route 切**,/login 只拿登入要用的元件,圖表很重的 dashboard 不會被一起送出去。他點名這由 Webpack 或 Vite 配合 router 動態載入完成,讓概念落地成具體工具。最後他做了一個抽象上升:code splitting 只是 **lazy loading** 這個更大心智模型的一個實例,而 lazy loading 的對立面是 eager loading——載入時機可以綁在捲動、換頁或點擊上,全都是為了讓 Core Web Vitals 更好。

AI 補充「按 route 切」是起點不是終點,值得補完整套策略:**第一刀切路由**(收益最大、風險最低);**第二刀切重量級依賴**——圖表庫、富文字編輯器、日期選擇器這類幾百 KB 但只在特定互動後才用到的東西,用動態 import 延後;**第三刀是 vendor 分離**,把不常變的第三方套件單獨成 chunk,讓使用者的快取在你每次發版時仍然有效。同時要知道 lazy loading 的**反效果**:切得太碎會製造大量小請求與瀑布式的依賴鏈,反而更慢;而在使用者點下去之後才開始載入,會把延遲從載入期搬到互動期——變成 INP 的問題。成熟的做法是搭配 prefetch:閒置時或滑鼠移到連結上時先偷偷載好,讓使用者感覺不到等待。作者只講了「延後」,沒講「預先」,但兩者其實是一組。

code splitting

程式碼分割

把應用程式的 JavaScript 拆成多個 chunk,只在需要時載入對應的部分。

最有效的第一刀是按路由切,第二刀是把重量級但低頻的依賴(圖表、編輯器)動態 import。要小心切太碎:大量小請求與依賴瀑布會讓總時間反而變長。

相關術語: lazy loading (一種實作)、module bundler (由它執行)

出處:第 16 段「Code splitting 與 lazy loading」

module bundler

模組打包工具

分析模組依賴關係、把原始碼轉換並打包成瀏覽器可載入檔案的工具。

Webpack 是最成熟通用的,Vite 開發時走原生 ESM 所以啟動極快、production 才打包。除了打包,它們也負責 tree shaking(移除沒用到的匯出)與 cache busting 的雜湊檔名(見第 10 段)。

相關術語: code splitting (提供能力)、cache busting (實作者)

出處:第 16 段「Code splitting 與 lazy loading」

lazy loading

延遲載入

把資源的載入推遲到真正需要的那一刻,而不是一開始就全部載入。

除了 JS chunk,也適用於圖片的 loading lazy 屬性、路由元件與資料。它的風險是把延遲搬到互動當下,所以成熟做法會配合 prefetch:在閒置時或使用者顯露意圖時(hover)先偷偷載好。

相關術語: eager loading (相反)、code splitting (包含)

出處:第 16 段「Code splitting 與 lazy loading」

eager loading

積極載入

在使用者實際需要之前就先把資源全部載入。

它不是錯誤選項,只是預設值不該是它。對確定馬上要用的關鍵資源(首屏字體、主視覺圖),eager 反而是對的——用 preload 提前抓,避免它被排在資源佇列後面。要點是**依重要性分配**,而非一律延後。

相關術語: lazy loading (相反)

出處:第 16 段「Code splitting 與 lazy loading」

留給下一段 JavaScript 送得剛剛好了,但如果第一個畫面本身就得等 JavaScript 跑完才出現呢?下一段回到更根本的問題:畫面到底該在哪裡被渲染。

17. 渲染策略:CSR、SSG、ISR、SSR 32:00–35:15

現代元件框架(React、Vue、Angular)的問題是進站看到白畫面:載入空 HTML,跑完 render function 才看得到東西——這是 **client-side rendering**,SPA 要先拿靜態檔、再抓動態資料、最後才渲染,對效能與 SEO 都不利。替代方案依序是:靜態網站先在 server 預先渲染好直接送 HTML/CSS;內容會變的(例如部落格)用 **incremental static generation**,CMS 觸發 rebuild 只重生變動的頁面;最後是 **server-side rendering**,前端 server 去後端拿資料、在 server 上渲染再把完整 HTML 送回,白畫面沒了但頁面還不能互動,得經過 **hydration** 把 virtual DOM 掛上既有 HTML。作者對 SSR 的態度很保留:只有真的需要極致效能或 SEO 才用,否則就像「為了買菜造一台 F1 賽車」。

CSR 的請求時序圖:拿靜態檔 → 抓動態資料 → 才渲染,白畫面卡在哪一步看圖最快
32:45 · CSR 的請求時序圖:拿靜態檔 → 抓動態資料 → 才渲染,白畫面卡在哪一步看圖最快
incremental static generation 的 CMS → rebuild → 部分靜態檔流程圖
33:25 · incremental static generation 的 CMS → rebuild → 部分靜態檔流程圖
SSR + hydration 的時序圖,virtual DOM 掛上既有 HTML 這一步只有畫出來才清楚
34:22 · SSR + hydration 的時序圖,virtual DOM 掛上既有 HTML 這一步只有畫出來才清楚
承上 接住上一段留下的根本問題:JavaScript 已經送得剛剛好了,但如果第一個畫面本身就得等 JavaScript 跑完才出現,切分再細也救不了。

推理因為上一段的所有手段都在「送多少 JS」這個維度上,所以這一段換維度:**畫面在哪裡被渲染**。作者用一個所有人都有實感的症狀開場——現代元件框架進站的白畫面——並解釋成因:拿到的是空 HTML,得等 render function 跑完才有東西。這是 client-side rendering,對效能與 SEO 都不利。接著他按「內容變動頻率」排出一條光譜:內容不變 → 建置時預先渲染成靜態檔;內容會變但不頻繁 → incremental static generation,CMS 觸發只重生變動的頁;內容每次都不同 → server-side rendering,在伺服器抓資料渲染完再送出。SSR 解掉白畫面,但引入 **hydration**:頁面看得到卻還不能互動,得等 JS 執行、建好 virtual DOM 掛上既有 HTML。作者對 SSR 的態度很保留——「為了買菜造一台 F1 賽車」——只有真的需要極致效能或 SEO 才用。

AI 補充這條光譜的**判準**可以講得比作者更明確:不是「哪個技術比較先進」,而是**這一頁的內容在什麼時候才能確定**。建置時就確定(部落格、文件、行銷頁)→ SSG;建置時確定但會過期(商品列表、新聞)→ ISR;每個使用者每次請求都不同(個人化推薦、儀表板)→ SSR 或乾脆 CSR。同一個網站的不同路由用不同策略是完全正常的,Next.js 這類框架正是為此設計。另外要補 hydration 的真正代價:使用者會遇到一段**看得見卻按不動**的空窗期,這對 INP(第 15 段)是直接的傷害,而且諷刺的是,SSR 為了消除白畫面反而讓這段空窗更容易被察覺——因為畫面已經在那裡了。這也是近年 islands architecture、React Server Components、partial hydration 這些方向要處理的問題:**只 hydrate 真的需要互動的那幾塊**。最後替作者的保留意見補一個更精確的判準:SSR 的複雜度成本主要不在渲染本身,而在**你現在有一台需要維運的伺服器**——快取、記憶體洩漏、冷啟動、以及所有「在瀏覽器有、在 Node 沒有」的 API 差異。如果你的 SEO 需求只涵蓋幾個公開頁面,SSG 幾乎總是更划算的選擇。

術語:static site generation

client-side rendering

客戶端渲染

伺服器只回傳空的 HTML 外殼,畫面完全由瀏覽器執行 JavaScript 後產生。

它的代價是首次繪製慢與爬蟲不友善,收益是伺服器極簡(純靜態檔)、後續導航極快(不必重新載入整頁)。對登入後才看得到的應用程式後台,CSR 往往仍是最合理的選擇——反正不需要 SEO。

相關術語: server-side rendering (對照組)、SPA (典型架構)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

SPA

單頁應用

只載入一次 HTML 外殼,之後所有畫面切換都由前端路由在瀏覽器內完成的應用架構。

它讓導航感覺像原生應用,代價是你得自己接管瀏覽器原本免費提供的東西:路由、捲動位置、焦點管理、無障礙的頁面切換通知。最後這幾項是 SPA 最常被忽略、也最常做錯的部分。

相關術語: client-side rendering (通常採用)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

static site generation

靜態網站生成

在建置階段就把所有頁面預先渲染成 HTML 檔案,執行時只需回傳靜態檔。

效能與可靠性的上限——沒有伺服器運算,直接由 CDN 送出。限制是內容一變就得重新建置整站,站一大建置時間就成為瓶頸,這正是 ISR 要解的問題。

相關術語: incremental static generation (改良版)、CDN (最佳搭配)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

incremental static generation

增量靜態生成

只重新產生內容有變動的那些靜態頁面,而不是整站重建。

Next.js 的 ISR 更進一步支援「過期後於背景重新產生」:使用者先拿到舊版本,同時觸發背景更新,下一位就拿到新的。它在靜態的效能與動態的新鮮度之間取得平衡,代價是你要接受短暫的資料過時。

相關術語: static site generation (改良自)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

server-side rendering

伺服器端渲染

每次請求都在伺服器上執行框架的渲染、把完整 HTML 送給瀏覽器。

解掉白畫面與 SEO,代價是你多了一台需要維運的伺服器,以及 hydration 帶來的「看得到但按不動」空窗。判準是內容能不能在建置時確定——不能,才輪到 SSR。

相關術語: client-side rendering (對照組)、hydration (必要後續)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

hydration

水合

在伺服器渲染出的 HTML 上執行 JavaScript、附加事件與狀態,讓靜態畫面變成可互動。

它是 SSR 的隱藏成本:使用者看得到內容卻按不動,直到 hydration 完成。近年的 islands architecture、partial hydration 與 React Server Components 都在處理同一個問題——只 hydrate 真正需要互動的區塊。

相關術語: server-side rendering (後續步驟)、INP (影響)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

virtual DOM

虛擬 DOM

以 JavaScript 物件描述介面結構,比對前後差異後再套用到真實 DOM 的技術。

它的價值不是「比較快」——直接操作 DOM 永遠更快——而是讓你能用宣告式的方式寫 UI,把「怎麼更新」交給框架。Svelte 與 Solid 證明了不用 virtual DOM 也能達成宣告式,靠的是編譯期分析。

相關術語: reconciliation (運作於)、hydration (建立於)

出處:第 17 段「渲染策略:CSR、SSG、ISR、SSR」

見仁見智 34:53
「that's like building an F1 car to go to the groceries」
這個比喻對「為了 SEO 就全站 SSR」的批評是對的,但把 SSR 一概說成過度設計在今天偏保守。Next.js App Router、Remix、Nuxt 已經把 SSR 變成預設路徑,運維成本大幅下降;而 React Server Components 與 partial hydration 也在削減他點出的 hydration 代價。比較準確的判準不是「要不要 SSR」,而是**逐路由**決定:內容在建置時就能確定的用 SSG,需要個人化的才用 SSR。
依據: Next.js App Router(2023 起預設 Server Components)、Remix、Nuxt 3 皆以 SSR 為預設渲染模式
留給下一段 畫面渲染的問題解決了,但還有一類資料不遵守「請求—回應」的節奏:伺服器要主動、持續地推東西過來。這是最後一段的主題。

18. 即時通訊:polling、WebSocket、SSE 35:15–38:02

最後一個概念,也是作者強調前端要能碰資料層的理由。不走 request-response 週期的即時通訊有三種:**polling** 一直打同一個 endpoint 直到狀態改變,用 setTimeout 就能做、很簡單但打太多次、會有 race condition、不好 scale;**WebSocket** 開一條雙向通道,適合聊天這種雙邊都在送訊息的場景,但 overhead 大、很吃 server 資源;而 AI 應用的通訊是**單向不對稱**的——你送一個 query,然後 server 一直吐 token 回來。答案是 **server-sent events**:送一則訊息建立對話,然後在那個 endpoint 上持續接收 server 的更新。他點名這就是多數 LLM 應用的做法,你打開 ChatGPT 或 Claude 的 network 面板看那個 conversation 請求,回應就是一連串 event stream——不是 WebSocket,也不是 polling。

polling / WebSocket / SSE 三種方案並排的對照圖
35:48 · polling / WebSocket / SSE 三種方案並排的對照圖
SSE 的不對稱通訊圖:一則請求對上大量 token 回傳,這正是 LLM 應用的形狀
36:58 · SSE 的不對稱通訊圖:一則請求對上大量 token 回傳,這正是 LLM 應用的形狀
承上 接住上一段留下的最後一類問題:畫面渲染解決了,但有一類資料不遵守「請求—回應」的節奏,伺服器需要主動且持續地推送。

推理因為前面所有架構都建立在 client 發問、server 回答的模型上,所以最後一段要補上這個模型涵蓋不到的情況。作者用同一套方法——列出選項、逐一指出代價、再讓需求決定答案。**polling** 最簡單,setTimeout 就能做,代價是打太多次、有 race condition、scale 不好;**WebSocket** 開雙向通道,適合聊天這種兩邊都在送的場景,代價是 overhead 大、很吃伺服器資源。然後他丟出決定性的觀察:**AI 應用的通訊是不對稱的**——你送一個 query,server 吐回幾千個 token。既然是單向,用雙向通道就是浪費。於是 **server-sent events** 成為答案。他最後給了一個可以立刻自己驗證的證據:打開 ChatGPT 或 Claude 的 network 面板看那個 conversation 請求,回應就是一串 event stream。

AI 補充SSE 有兩個作者沒提、但實作時一定會撞到的特性。**好處**:它跑在普通的 HTTP 上,所以 CDN、代理、認證、壓縮這些既有基礎設施全部照用,而且瀏覽器的 EventSource 內建自動重連與 Last-Event-ID 續傳——這些在 WebSocket 上全都得自己寫。**限制**:在 HTTP/1.1 下每個網域的並行連線數上限是 6,幾個分頁一開就會互相卡住(升上 HTTP/2 就沒這問題);另外原生 EventSource 只支援 GET、不能自訂標頭,所以要帶 Authorization 的場合通常改用 fetch 手動讀 stream——這也是多數 LLM SDK 實際的做法。至於選擇標準,可以收成一句話:**只有伺服器要說話就用 SSE,雙方都要頻繁說話才用 WebSocket,簡單且低頻的狀態查詢用 polling 就好**。這也正好呼應這支影片從頭到尾的態度——先問需求的形狀,再選技術,而不是反過來。

polling

輪詢

客戶端定期重複請求同一個端點,直到取得期望的狀態變化。

實作成本最低,而且完全不需要伺服器端的特殊支援。改良版是 long polling:伺服器把請求掛住直到有資料才回應,減少空轉的請求數。適合低頻、非即時的狀態查詢,例如確認一筆付款有沒有完成。

相關術語: server-sent events (被它取代)、WebSocket (對照組)

出處:第 18 段「即時通訊:polling、WebSocket、SSE」

WebSocket

WebSocket

在單一 TCP 連線上建立全雙工通道,讓伺服器與瀏覽器都能主動送訊息。

它從 HTTP 升級而來,之後就脫離 HTTP 語意——所以快取、標準認證、部分代理與負載平衡器的處理都要另外設計。適用判準很單純:**雙方都要頻繁主動送訊息**,例如聊天、協作編輯、多人遊戲。

相關術語: server-sent events (對照組)、polling (對照組)

出處:第 18 段「即時通訊:polling、WebSocket、SSE」

server-sent events

伺服器推送事件

伺服器透過一條長連線持續向客戶端單向推送事件的 HTTP 標準。

瀏覽器端用 EventSource API,內建自動重連與 Last-Event-ID 續傳。因為它就是普通 HTTP,既有的 CDN、代理、認證與壓縮全部照用。限制是單向、HTTP/1.1 下受每網域六條連線的限制,且原生 API 只能發 GET。

相關術語: WebSocket (更輕量的替代)、polling (取代)

出處:第 18 段「即時通訊:polling、WebSocket、SSE」

race condition

競態條件

結果取決於多個非同步操作的完成順序,而該順序無法保證。

在 polling 與一般資料抓取上最常見的版本是:後發的請求先回來,舊資料覆蓋了新資料。解法是給每次請求標記序號或用 AbortController 取消過期的請求——React Query、SWR 這類函式庫已經內建這個處理。

相關術語: polling (常見問題)

出處:第 18 段「即時通訊:polling、WebSocket、SSE」

event stream

事件串流

以 text/event-stream 格式在單一 HTTP 回應中連續傳送的一系列事件。

格式極簡:每個事件是幾行 data: 開頭的文字,以空行分隔。這就是你在 ChatGPT 或 Claude 的 network 面板裡看到的東西,也是所有 LLM 串流回應的底層形式——理解它,你就知道打字機效果不是動畫,是真的一段段收到。

相關術語: server-sent events (傳輸格式)

出處:第 18 段「即時通訊:polling、WebSocket、SSE」

留給下一段 總結收束

4. 總結

這支影片的推理鏈可以壓成一條線:**AI 把瓶頸從「寫」搬到「驗證」→ 所以架構的目標變成讓變更容易被驗證 → 而最有效的手段是縮小每次變更的爆炸半徑 → 縮小的方法是把系統切成小而獨立、由單一團隊擁有的垂直切片。** 切分的依據來自 Conway's law:想要小而獨立的團隊,就得有小而獨立的系統。後端切成 microservices,前端切成 microfrontends 加一個薄 shell,兩邊對接成 vertical slice。接下來的九個概念,其實都是在還這一刀欠下的債——跨網路的雜事重複了用 API gateway 收攏;資料形狀與擁有權沒解決用 BFF;每層都是單機用 load balancing;技術棧太雜用 Docker 與 orchestration;機房離使用者太遠用 CDN;團隊各自出貨導致視覺分歧用 design system;design system 沒接上 AI 用 design-to-code MCP;程式碼散落讓 agent 看不見全貌用 monorepo。 傳統議題收完後,作者插入 MCP UI 作為前沿——當 LLM 回的不只是文字而是 UI 元件,前端要怎麼接。然後換到體感維度:Core Web Vitals 把「好慢」拆成 LCP、INP、CLS 三個可歸因的數字,critical rendering path 解釋數字為什麼難看,code splitting 處理送太多 JavaScript,渲染策略(CSR → SSG → ISR → SSR + hydration)處理畫面該在哪裡生成,最後 server-sent events 補上請求—回應模型涵蓋不到的即時推送。 真正該帶走的不是這二十個名詞,而是它們共用的提問順序:**這件事卡住了誰?成本落在哪一邊?有沒有一個切法能讓爆炸半徑變小、讓驗證變快?**

勘誤總整理

確定錯誤/已過時見仁見智(取決於版本或情境)

段落原話(transcript 逐字)說明
2. 從單體到微服務:團隊撐不住了
1:45
「as many as you can feed with one pizza」作者剛說完這條規則叫 two pizzas team,緊接著卻把它描述成「一個披薩餵得飽」。Amazon 的原始規則是**兩個**披薩餵得飽的人數(約 5–9 人),一個披薩會把上限壓得比他自己給的 5–9 人還低,前後矛盾。他下一句「有了 AI 就變成 one pizza team」才是刻意的引申。
依據: Jeff Bezos 的 two-pizza team rule,Amazon 內部沿用至今的說法為 two pizzas
6. API Gateway:把 edge functions 收成一次
9:55
「HTTPS it's likely less performant than the HTTP」這個說法以今天的標準過度簡化了。TLS 1.3 把 handshake 壓到 1-RTT、session resumption 可到 0-RTT,開銷通常只有個位數毫秒;而且 HTTP/2 與 HTTP/3 在瀏覽器上都**只**在 TLS 之上啟用,所以走 HTTPS 反而拿得到多工與更好的壅塞控制,整體常常更快。內部服務間改走純 HTTP 現在也不再是推薦做法——zero trust 與 service mesh 的主流意見是內網一律 mTLS,把加密成本交給基礎設施。
依據: RFC 8446(TLS 1.3, 2018);主流瀏覽器僅在 TLS 上支援 HTTP/2 與 HTTP/3
8. Load balancing:單台 server 的天花板
14:05
「it can usually satisfy up to 2,000 to 10,000 concurrent requests」這個區間只在「幾乎純 I/O、每個請求 CPU 工作極少」的前提下成立,作者沒有講出這個前提。一旦每個請求有 JSON 序列化、模板渲染、加密或任何同步運算,Node.js 的單執行緒事件迴圈會讓實際承載量掉到數百甚至更低。反過來說,純轉發的代理型工作可以遠高於一萬。當成數量級的直覺可以,當成容量規劃的依據不行——實際數字只能靠壓測得出。
依據: Node.js 單執行緒事件迴圈模型;承載量取決於每請求的 CPU 時間與 I/O 比例
10. CDN:跟光速借時間
19:58
「whenever the server pushes a new version, that's called cache invalidation」這個定義把兩件事混在一起了。cache invalidation 指的是**讓既有的快取項目失效**(CDN 上叫 purge),是一個明確的清除動作;「server 推上新版本」本身並不會讓舊快取失效,除非你主動 purge,或是用下一句他提到的 cache busting 讓新版本有新的網址。實務上正是因為 invalidation 不可靠,現代前端才幾乎全面改用內容雜湊檔名來繞過它。
依據: CDN 供應商(Cloudflare、Fastly、CloudFront)皆將 invalidation/purge 定義為主動清除既有快取項目的操作
17. 渲染策略:CSR、SSG、ISR、SSR
34:53
「that's like building an F1 car to go to the groceries」這個比喻對「為了 SEO 就全站 SSR」的批評是對的,但把 SSR 一概說成過度設計在今天偏保守。Next.js App Router、Remix、Nuxt 已經把 SSR 變成預設路徑,運維成本大幅下降;而 React Server Components 與 partial hydration 也在削減他點出的 hydration 代價。比較準確的判準不是「要不要 SSR」,而是**逐路由**決定:內容在建置時就能確定的用 SSG,需要個人化的才用 SSR。
依據: Next.js App Router(2023 起預設 Server Components)、Remix、Nuxt 3 皆以 SSR 為預設渲染模式

5. 推薦三個下一步

1. 往下挖深:Module Federation 與微前端的實際落地

影片把微前端講到「shell 載入各微前端」就停住了,沒有回答最實際的三個問題:多個微前端怎麼共用同一份 React 而不重複下載、shell 傳下去的 global state 怎麼避免變成沒有型別的隱性 API、以及樣式怎麼隔離。這是從概念走到能上線的那一段。

YouTube 搜尋:Module Federation micro frontends tutorial micro frontend shared dependencies React micro frontend css isolation

2. 往旁邊對照:React Server Components 與 islands architecture

影片對 SSR 的態度停在「像造 F1 去買菜」,但它點出的 hydration 代價(看得到卻按不動)正是近年整個生態在解的題目。把 RSC、islands、partial hydration 拿來對照,你會看到「只 hydrate 需要互動的那幾塊」如何改寫渲染策略的取捨表。

YouTube 搜尋:React Server Components explained islands architecture partial hydration Astro vs Next.js rendering

3. 往上應用:把 SSE 串流接進自己的 LLM 應用

影片給了「LLM 應用用 server-sent events」這個結論,也給了打開 network 面板自己驗證的方法,但沒有走到實作。親手寫一次串流端點與前端接收,你會同時撞到它沒提的兩個坑:原生 EventSource 不能自訂標頭,以及 HTTP/1.1 下每網域六條連線的限制。

YouTube 搜尋:server sent events streaming LLM tutorial EventSource vs fetch streaming React OpenAI streaming response frontend

📄 全部影片 · 主題區: 前端底層與系統設計