前端架構演化史:每一站解決了什麼,又製造了什麼

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

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

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

1. Outline

  1. 起點 · Every Frontend Architecture Pattern Explained in 23 Minutes
    把前端架構史講成一條被問題推著走的因果鏈:靜態頁面 → MVC → SPA → BFF → SSG/ISR/SSR/RSC → 模組化單體 → micro-frontend,每一站用同一張六軸卡片(擴展性、效能、複雜度、團隊規模、產品價值、成本)評分,最後收成一份可以照著跑的架構稽核。

2. YouTuber 的思維推導

Every Frontend Architecture Pattern Explained in 23 Minutes

theSeniorDev · 22m33s · 字幕 en · vision=on (使用者指定 vision=true;這支是投影片+白板型影片,每種架構都配一張示意圖與一張六軸評分表(擴展性/效能/複雜度/團隊規模/產品價值/成本),不看圖會漏掉整個比較基礎。) · YouTube

預估 vs 實際耗時
階段預估實際
fetch 6s 1s
segment 1m15s 5m00s
shot 50s 6s
analyze 10m00s 15m00s
render 5s –

作者的出發點是一個面試現象:被拒的人往往技術沒問題,只是講不出取捨,於是聽起來像中階。他的解法不是給一張「該用什麼」的對照表,而是把整個前端架構史講成一條被問題推著走的因果鏈——每一站都是為了解決上一站的痛點而生,而每一個解法又製造出下一站要解決的新痛點。靜態頁面快但沒互動,於是 MVC 把邏輯搬上伺服器;MVC 整頁重載又前後端緊耦合,於是 SPA 把邏輯搬進瀏覽器;SPA 送出太多 JavaScript、首屏空白,於是 SSG/ISR/SSR 把渲染搬回伺服器;SSR 又製造出 hydration 的延遲,於是 React Server Components 只送需要互動的那部分。

同一時間另一條線在跑:客戶端變多,後端被 BFF 切開;SPA 本身變大,於是切成模組化單體;團隊再變大,才切成 micro-frontend。他用同一張六軸卡片(擴展性、效能、複雜度、團隊規模、產品價值、成本)替每一站評分,讓「架構沒有好壞、只有取捨」變成看得見的東西——而且他一再往回踩煞車:clean architecture 在前端多半是過度設計、Next.js 不要過早搬、小公司做 micro-frontend 是自找麻煩。最後他把整條鏈收成一個可執行的動作:稽核自己的 code base,寫下你在哪一站、為什麼在這裡、下一步是哪裡,並把面試回答從「我們用 React」升級成一句同時包含渲染策略、repo 結構與未來方向的話。

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

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

  1. 開場:面試考的是架構取捨 → 既然架構是被問題推著走的,那就得先問:最早的網頁是什麼樣子,是什麼問題把它推向下一站?
  2. 從靜態頁面到 MVC → MVC 解決了動態內容,但整頁重載的體驗還是很差。下一個問題是:能不能不重載就更新畫面?
  3. SPA:邏輯搬到瀏覽器那一刻 → 邏輯從伺服器搬到瀏覽器,是一次程度上的移動而不是非黑即白。在往下走之前,需要一把尺來量這個程度。
  4. thick client 與 thin client → 到目前為止都只有一個 client。但當手機、平板、多種裝置同時來要資料時,後端那一側會發生什麼事?
  5. BFF 與 GraphQL:後端被切開 → 後端那一側的分裂解決了,但前端最初的痛點還在原地:SPA 仍然送出太多 JavaScript,使用者仍然盯著空白畫面。
  6. SSG 與 ISR:回到伺服器產頁面 → SSG 與 ISR 解決了速度與 SEO,但它們的前提是頁面對所有人都一樣。那需要個人化、需要真互動的頁面怎麼辦?
  7. SSR、hydration 與 React Server Components → 這一整條渲染演化把效能推到極致,但每一步都在加東西。那總帳算下來,代價是什麼?
  8. 渲染策略的代價與過早遷移的警告 → 渲染這條線走到底了,但 SPA 內部本身從頭到尾沒有變過。當它自己大到難以維護時,該怎麼辦?
  9. 模組化前端單體:先畫出邊界 → 邊界要怎麼畫才對?這時候很自然會想去借經典軟體架構的成熟答案。
  10. clean architecture 在前端值不值得 → 如果邊界光靠紀律守不住,那還有一種更硬的辦法——把邊界變成部署的邊界。
  11. micro-frontend:企業級的最後一站 → 六站走完了,但知道有哪些架構跟能在面試裡講清楚自己的架構是兩回事。最後需要一個把這些變成自己的東西的動作。
  12. 架構稽核與資深的回答長什麼樣

3. 逐段說明

Every Frontend Architecture Pattern Explained in 23 Minutes

1. 開場:面試考的是架構取捨 0:00–0:43

作者開門見山:資深前端面試考的不是寫程式,而是架構取捨。monolith 與 micro-frontend 差在哪、clean 還是 hexagonal、SSR 還是 SSG——答不出來就只會被歸類成中階。這支影片要走一遍前端架構的演化:靜態頁面 → MVC → SPA → BFF → 模組化單體 → micro-frontend,每一站講取捨與適用時機,最後給一份可以照著做的架構稽核清單。

承上 前情提要裡最關鍵的背景是:資深面試評的不是你會不會寫,而是你能不能說出選擇背後的理由。這一段就從這個背景開場。

推理作者一開口就把評分標準換掉:資深前端面試考的不是寫程式,是架構取捨。他用四個具體的對比題證明這件事——monolith 對 micro-frontend、clean 對 hexagonal、SSR 對 SSG——並直接說出後果:答不出來,你聽起來最多就是中階。有了這個標準,整支影片的形式才成立:不是列出所有架構,而是走一遍它們為什麼依序出現,每一站都問取捨與適用時機,最後給一份可以照著跑的稽核清單。

AI 補充作者沒有明說的是,為什麼「取捨」會成為資深的判準。原因是架構決策幾乎沒有正確答案,只有在特定條件下比較不痛的答案。一個只會說「我們用 Next.js」的人,面試官無法判斷他是想清楚才選的、還是跟著範本走;而一個能說出「我們為了 SEO 選 SSG,代價是內容更新要重新 build,所以我們用 ISR 補上」的人,等於當場展示了他做決策的方式。另外值得先建立的心理準備是:這支影片講的順序是**歷史順序**,不是好壞順序。後面出現的架構並不「比較好」,它們只是解決了更後面才出現的問題,同時付出更高的複雜度。

留給下一段 既然架構是被問題推著走的,那就得先問:最早的網頁是什麼樣子,是什麼問題把它推向下一站?

2. 從靜態頁面到 MVC 0:43–2:22

起點是純 HTML/CSS 加一點 JavaScript:快,但零互動,像一本雜誌。第一個架構風格 MVC 因此登場——Django、Rails、.NET 都是這樣開始的:view 還是靜態 HTML,但由跑在伺服器上的 model 與 controller 把資料與模板混出客製化的頁面。代價是每換一頁就整頁重載、效能與擴展性都差,前後端緊密耦合,而且框架鎖定嚴重,換框架幾乎等於重寫。好處是複雜度低、能做的邏輯比純靜態頁多。

MVC 的三個角色與它在伺服器端的位置
1:45 · MVC 的三個角色與它在伺服器端的位置
MVC 在六個評分軸上的位置,後面每種架構都會用同一張表比較
2:15 · MVC 在六個評分軸上的位置,後面每種架構都會用同一張表比較
承上 承上:既然要看架構被什麼問題推著走,就從最原始的那一站開始——純靜態頁面。

推理起點是純 HTML 與 CSS 加一點點 JavaScript:極快,但零互動,作者形容它像雜誌或報紙,只有文字和圖片。這個「零互動」就是推動下一站的力量,於是 MVC 出現——Django、Rails、ASP.NET 都是這樣起家的。它的作法是:view 仍然是產出的 HTML,但由跑在伺服器上的 model 與 controller 用 PHP、Python 或 Java 把資料與模板混合,吐出客製化的頁面。作者接著用六軸卡片替它評分:擴展性最低、效能不佳、複雜度低、團隊規模小,適合 CRUD 應用、小團隊與快速原型。代價是每換一頁就整頁重載、前後端緊密耦合,還有嚴重的框架鎖定——從一個框架換到另一個幾乎不可能。

AI 補充這裡有一個值得補上的細節:MVC 的「view 在伺服器」是它所有優缺點的共同來源。因為畫面是伺服器組出來的,所以 SEO 天生就好、首屏天生就快、也不需要前端工程師;但也因為畫面是伺服器組出來的,任何互動都得回伺服器要一份新的 HTML,於是整頁重載無法避免。理解這一點,後面每一次「把渲染搬來搬去」的演化就都能被同一句話解釋:**渲染發生在哪裡,決定了誰快、誰慢、誰耦合**。另外要注意作者說的「框架鎖定」在今天仍然成立,而且是 MVC 這一站被淘汰的真正原因之一——樣板語法、ORM、路由全部綁在一起,換框架等於重寫。

MVC

模型-視圖-控制器

把資料(model)、畫面(view)與流程控制(controller)分開的架構模式。

它在 2000 年代初期幾乎定義了 web 開發:Rails、Django、Laravel 都以它為骨架。要注意伺服器端 MVC 與前端框架講的 MVC 不是同一件事——前者的 view 是產出的 HTML 字串,後者的 view 是瀏覽器裡持續存在的元件。它真正的貢獻不是那三個字母,而是把「資料」與「呈現」分開這個習慣,這個習慣一路延續到今天的每一個框架。

相關術語: tight coupling (它的代價)

出處:第 2 段「從靜態頁面到 MVC」

tight coupling

緊密耦合

兩個模組彼此知道太多細節,改動一邊幾乎一定要改另一邊。

在伺服器端 MVC 裡,樣板直接讀 model 的欄位、controller 直接決定畫面結構,所以前端改版常常要動到後端程式碼。耦合本身不是罪——耦合換來的是簡單與速度,小專案裡這筆交易很划算。它變成問題是在人變多之後:緊耦合讓兩個團隊沒辦法各自出貨,這正是後面每一次拆分的動機。

相關術語: framework lock-in (常一起出現)

出處:第 2 段「從靜態頁面到 MVC」

framework lock-in

框架鎖定

應用與特定框架的慣例綁得太深,換框架的成本接近重寫。

鎖定的深度取決於框架滲透到多少層。MVC 框架同時包辦路由、ORM、樣板與表單處理,滲透極深;而一個只負責渲染的前端函式庫滲透較淺。判斷自己被鎖多深的方法很直接:把框架名稱從程式碼裡拿掉,還剩下多少可用的邏輯?這個問題在後面談 clean architecture 時會再出現一次。

相關術語: MVC (典型案例)

出處:第 2 段「從靜態頁面到 MVC」

留給下一段 MVC 解決了動態內容,但整頁重載的體驗還是很差。下一個問題是:能不能不重載就更新畫面?

3. SPA:邏輯搬到瀏覽器那一刻 2:22–4:07

JavaScript 起飛後進入單頁應用時代:前端用 React、Vue 或 Angular 寫,後端退化成提供資料的 API,驗證、授權與狀態管理都搬到瀏覽器。換來的是不重載就能更新畫面的互動性、更好的擴展性與效能。作者點出一個關鍵的副作用:SPA 誕生的那一刻,「前端工程師」這個職位才誕生,因為邏輯被搬過來了,團隊可以更大、產品可以更複雜。代價是 JavaScript 太多、首次載入很慢,而且初始畫面是空的,SEO 很差。

SPA 與後端 API 的關係圖,對照前一段的 MVC
2:55 · SPA 與後端 API 的關係圖,對照前一段的 MVC
SPA 的六軸評分,與 MVC 的差距一目了然
3:45 · SPA 的六軸評分,與 MVC 的差距一目了然
承上 承上:整頁重載的體驗問題必須解決,而 JavaScript 的成熟讓「不重載就更新畫面」變成可能。

推理作者把 SPA 描述成一次重心轉移:畫面用 React、Vue 或 Angular 在瀏覽器裡建,後端退化成提供資料的 API——他特別說「那個 API 就是我們以前的 view,但現在它只是個 model」。驗證、授權與狀態管理跟著搬到前端,於是不重載就能更新畫面。他接著點出這件事最重要的社會學後果:**SPA 誕生的那一刻,前端工程師這個職位才誕生**,因為邏輯被搬過來了,團隊可以更大、產品可以更複雜,儀表板與 SaaS 這類產品才成為可能。六軸上 SPA 幾乎每一項都比 MVC 高,但代價寫在最後:送出太多 JavaScript、首次載入很慢,而且初始畫面是空的,SEO 很差。

AI 補充「後端退化成 model」這個說法很傳神,但要補上它省略的一步:搬走的不只是渲染,還有**狀態的所有權**。伺服器渲染時,畫面就是資料當下的樣子,沒有「同步」這個問題;SPA 則在瀏覽器裡養了一份資料副本,於是快取、失效、樂觀更新、race condition 全部成為前端的日常工作——這也是為什麼後來會冒出那麼多狀態管理工具。至於 SEO 這一點,今天要打點折扣:主流搜尋引擎已經會執行 JavaScript 再索引,純 SPA 不再等於搜不到;但執行有排程延遲、非搜尋引擎的爬蟲(社群分享的預覽卡片)多半不跑 JavaScript,所以「內容型網站別用純 CSR」的結論仍然成立,只是理由從「搜不到」變成「慢且不可靠」。

術語:client-side routing

SPA

單頁應用

只載入一次 HTML,之後靠 JavaScript 在瀏覽器內切換畫面的應用。

它的核心特徵是路由由前端接管:網址變了,但沒有向伺服器要新的文件。好處是切換瞬間完成、可以做轉場動畫、應用狀態不會在換頁時消失;代價是首次載入要付出整包 JavaScript 的下載與解析成本,而且瀏覽器的許多預設行為(上一頁、捲動位置、焦點管理)都得自己重新實作。

相關術語: client-side routing (它的核心機制)、thick client (典型形態)

出處:第 3 段「SPA:邏輯搬到瀏覽器那一刻」

client-side routing

客戶端路由

由瀏覽器內的 JavaScript 依網址決定顯示哪個畫面,不向伺服器請求新文件。

實作上靠 History API 改網址、再由路由器比對出對應元件。最容易被忽略的是它把無障礙與可用性的責任接了過來:換頁時螢幕閱讀器不會自動宣告新頁面、捲動位置不會自動重置、焦點會留在原地,這些都得手動處理。它也需要伺服器配合——任何路徑都要回傳同一份 HTML,否則使用者直接輸入深層網址會拿到 404。

相關術語: SPA (使其成立)

出處:第 3 段「SPA:邏輯搬到瀏覽器那一刻」

SEO

搜尋引擎最佳化

讓網頁內容能被搜尋引擎正確抓取、理解並排名的一系列作法。

對架構決策而言,關鍵問題只有一個:爬蟲拿到的第一份 HTML 裡有沒有內容。伺服器渲染的頁面直接就有;純客戶端渲染的頁面要等爬蟲執行 JavaScript 才有,而執行是排隊的、也不是每個爬蟲都做。社群平台產生分享預覽卡片時通常只讀初始 HTML 的 meta 標籤,完全不執行 JavaScript,這往往是比搜尋排名更立即的痛點。

相關術語: SPA (它的弱項)

出處:第 3 段「SPA:邏輯搬到瀏覽器那一刻」

見仁見智 4:18
「And because you get this initial empty page, you also have very poor SEO.」
在今天要打折扣。Google 等主流搜尋引擎已經會執行 JavaScript 後再索引,純 SPA 不等於搜不到。但執行有排程延遲、內容更新反映得慢,而且社群平台產生分享預覽時多半只讀初始 HTML 的 meta 標籤、完全不跑 JavaScript。所以結論仍然成立,理由要改成「慢且不可靠」,而不是「搜不到」。
依據: Google Search Central 文件說明 JavaScript 網站的兩階段索引(crawl → render queue → index)
留給下一段 邏輯從伺服器搬到瀏覽器,是一次程度上的移動而不是非黑即白。在往下走之前,需要一把尺來量這個程度。

4. thick client 與 thin client 4:07–5:05

在往下走之前,作者插入一個貫穿全片的座標軸:thin client 把大部分邏輯交給後端,像靜態頁面;thick client 自己扛大量商業邏輯,把後端當成儲存空間。從 thin 走到 thick,就是不斷把邏輯往前端搬的過程。他刻意不展開優劣,只要求你記住這個軸,並且問自己:你的 client 應該厚到什麼程度?

thin 與 thick client 的對照軸,後面每個架構都可以放到這條軸上
4:35 · thin 與 thick client 的對照軸,後面每個架構都可以放到這條軸上
承上 承上:邏輯從伺服器搬到瀏覽器是程度問題,所以作者在這裡插入一把量這個程度的尺。

推理他刻意打斷演化敘事,先建立一個座標軸:thin client 把大部分邏輯交給後端,典型就是靜態頁面;thick client(或 fat client)自己扛大量商業邏輯,把後端更多地當成儲存空間用。從 thin 走到 thick,就是不斷把邏輯往前端搬的過程——也就是前面兩段發生的事。他明講不展開優劣,只要求你記住這條軸,並且問自己:你的 client 應該厚到什麼程度?

AI 補充作者把這條軸留白了,但它其實有幾個很實用的判準,值得補上。第一,**邏輯放在 client 的那一刻就不可信任**:任何驗證、價格計算、權限判斷,前端做的版本只能算體驗優化,後端一定要再做一次,否則就是漏洞。第二,**client 越厚,版本管理越痛**:使用者的瀏覽器裡跑的可能是三週前的舊版,而 thin client 每次進來拿到的都是最新的。第三,這條軸不是全有全無的,同一個應用可以在不同畫面上選不同厚度——這正是後面 React Server Components 在做的事:讓元件樹的一部分是 thin、一部分是 thick。

thin client

瘦客戶端

把大部分邏輯與狀態交給伺服器,自己主要負責呈現的客戶端。

它的優點幾乎都來自「沒有自己的狀態」:不需要同步、不會有舊版本在外面跑、首屏快、對裝置效能要求低。缺點是每個互動都要一次網路往返,在延遲高的網路下體驗會明顯變差。伺服器渲染的頁面、以及近年回潮的 HTMX 風格作法,都屬於這一側。

相關術語: thick client (對照組)

出處:第 4 段「thick client 與 thin client」

thick client

胖客戶端

在客戶端持有大量狀態與商業邏輯,把後端當成資料儲存的客戶端。

它換來的是即時反應與離線能力,代價是狀態同步、快取失效與版本落差全部變成前端的問題。一個實用的界線是:**呈現邏輯放前端,決策邏輯留後端**。價格、權限、庫存這類會影響金錢或安全的計算,前端可以先算一份給使用者看,但後端必須有權威版本。

相關術語: thin client (對照組)、SPA (典型實作)

出處:第 4 段「thick client 與 thin client」

留給下一段 到目前為止都只有一個 client。但當手機、平板、多種裝置同時來要資料時,後端那一側會發生什麼事?

5. BFF 與 GraphQL:後端被切開 5:05–7:53

行動裝置出現後,多種 client 打同一支 API,於是 BFF(backend for frontend)出現:每個前端應用配一個專屬後端,因為手機的畫面需要的是同一批資料的不同形狀,硬塞進單一 API 會變成科學怪人。作者強調這對前端的意義——BFF 通常由前端團隊自己擁有,於是前端工程師被推向全端。GraphQL 則解決 REST 的 overfetching 與 underfetching,但帶來 N+1 問題與圖思維的複雜度。結構上的收穫是:BFF 後面可以接很多微服務,後端團隊各自每天出貨,前端不被打斷,團隊因此可以長大。代價是耦合、單點故障、多一次網路往返,以及可觀的前期學習成本。

多個 client 各自對應一個 BFF 的切分圖
5:30 · 多個 client 各自對應一個 BFF 的切分圖
BFF 的六軸評分:效能反而略降,團隊規模與產品價值上升
7:35 · BFF 的六軸評分:效能反而略降,團隊規模與產品價值上升
承上 承上:前面談的都是單一 client 的厚薄,但行動裝置出現後,多個不同厚度的 client 開始打同一支 API。

推理作者的推理很直接:手機和桌機的畫面完全不同,可能要同一批資料但要的是不同形狀;硬塞進單一 API 會變成科學怪人,所以應該每個前端配一個專屬後端——這就是 BFF。接著他點出這對前端的意義:BFF 多半由前端團隊自己擁有,於是前端工程師被推向全端。GraphQL 則被放在同一條線上,因為它解決的是同一類問題的另一半——REST 的 overfetching 與 underfetching;但它也帶來 N+1 問題與用圖思考的複雜度。結構上真正的收穫在人:BFF 後面可以接一整排微服務,後端團隊各自每天出貨,前端團隊不被打斷,於是團隊規模可以長大。六軸上 BFF 幾乎全面高於 SPA,但他同時列出三個缺點——緊密耦合、擴展性上限、單點故障,而且多了一次網路往返、前期學習成本很高。

AI 補充這裡有一個需要澄清的觀念:**BFF 與 GraphQL 是兩個獨立的決定,經常被混在一起講**。BFF 是「誰擁有這層 API」的組織決策,你完全可以用 REST 寫 BFF;GraphQL 是「查詢語言長什麼樣」的技術決策,也可以直接暴露給 client 而沒有 BFF。作者把它們並排是因為它們常一起出現,但面試時分開講會顯得更清楚。另外「BFF 由前端團隊擁有」這句話的重量常被低估:它意味著前端團隊要接下部署、監控、on-call 與資安責任,這是真正的成本所在,比學 GraphQL 語法貴得多。至於 N+1 問題,它其實是 GraphQL 的架構特性——每個欄位各自解析,所以一個回傳一百筆的清單查詢,底下的關聯欄位就會觸發一百次呼叫;標準解法是 DataLoader 這類把同一輪的請求批次合併的機制。

術語:N+1 problem

BFF

前端專用後端

為每一種前端客戶端各自建立一層專屬 API,負責把下游服務的資料整形成該畫面需要的樣子。

它的價值在於把「畫面需要什麼形狀」這個問題留在最懂畫面的團隊手上,而不是逼所有 client 遷就同一份通用 API。它也是放共用關卡的好位置——驗證、限流、HTTPS 交握都只需要做一次。代價是多一層要部署與監控的服務,以及一次額外的網路往返;如果做得太薄,它會退化成沒有價值的轉發層。

相關術語: microservices (在其下游)、GraphQL (常見實作技術)

出處:第 5 段「BFF 與 GraphQL:後端被切開」

GraphQL

GraphQL

由客戶端在查詢中指定要哪些欄位的 API 查詢語言與執行規格。

它把「回傳什麼」的決定權從伺服器交給客戶端,因此同一個端點可以同時服務形狀需求不同的手機與桌機。代價是伺服器端變複雜:快取不再能靠網址、查詢深度與複雜度要設上限以免被惡意查詢打垮、還有 N+1 問題要處理。近年 REST 搭配針對畫面設計的端點又重新流行,正是因為這些成本。

相關術語: overfetching (解決對象)、N+1 problem (它的代價)

出處:第 5 段「BFF 與 GraphQL:後端被切開」

overfetching

過度抓取

API 回傳的資料比畫面實際需要的多,浪費頻寬與解析時間。

它的雙生兄弟是 underfetching——一次請求拿不齊,得再打好幾支端點才能湊出一個畫面,在行動網路上尤其痛,因為往返延遲比頻寬更致命。這兩個問題都源自同一件事:通用 API 的形狀是為所有人設計的,因此對誰都不剛好。BFF 和 GraphQL 是對這個問題的兩種不同解法。

相關術語: GraphQL (被它解決)

出處:第 5 段「BFF 與 GraphQL:後端被切開」

N+1 problem

N 加一問題

取得一份清單後,又為清單裡每一筆各發一次查詢,總共發出 N+1 次請求。

在 GraphQL 裡它幾乎是預設會發生的,因為每個欄位由各自的 resolver 獨立解析,沒人知道旁邊還有九十九個一樣的請求。標準解法是 DataLoader 這類批次載入器:把同一個事件迴圈輪次內的所有請求收集起來,合併成一次批次查詢再分發結果。這個問題在 ORM 的世界裡也是同一個名字、同一個原因。

相關術語: GraphQL (常見於)

出處:第 5 段「BFF 與 GraphQL:後端被切開」

microservices

微服務

把後端拆成多個可獨立開發、部署與擴展的小型服務。

它跟 BFF 是互補的:微服務讓後端團隊各自出貨,但也讓「一個畫面要打七支服務」變成常態,於是需要一層負責聚合的門面,那就是 BFF 或 API gateway。它跟本片後面的 micro-frontend 是同一個思路搬到瀏覽器:用部署邊界換取團隊的獨立性,代價都是複雜度與整合成本。

相關術語: BFF (在其上游)

出處:第 5 段「BFF 與 GraphQL:後端被切開」

留給下一段 後端那一側的分裂解決了,但前端最初的痛點還在原地:SPA 仍然送出太多 JavaScript,使用者仍然盯著空白畫面。

6. SSG 與 ISR:回到伺服器產頁面 7:53–9:43

後端問題解決了,前端仍然送出太多 JavaScript、使用者盯著空白畫面。於是 SSG、ISR、SSR 與 Next.js、Nuxt 這類 meta framework 登場。SSG 是「回到未來」:仍然用現代框架開發,但最後產出靜態頁面丟到 CDN,快到極點又便宜;代價是幾乎沒有互動性,內容要改就得重新 build、重新部署。ISR 是它的進化——依 TTL 在請求進來時判斷是否過期,過期就回資料源重新產生並替換 CDN 上的快取,內容因此能動態更新,但仍然撐不起真正的互動。

SSG 的流程:build 時產生靜態頁、丟到 CDN
8:30 · SSG 的流程:build 時產生靜態頁、丟到 CDN
ISR 的 TTL 與重新產生、替換快取的循環
9:15 · ISR 的 TTL 與重新產生、替換快取的循環
承上 承上:後端的分裂處理完了,但 SPA 送出太多 JavaScript、首屏空白這個原始痛點還沒被碰過。

推理作者的解法是把渲染搬回伺服器,而且他自己形容這是「回到未來」——回到最初那個靜態網頁的形態,只是這次帶著現代工具。SSG 的作法是:開發時仍然用 React 或 Vue,但 build 時就把頁面產成靜態檔案丟到 CDN,於是快到極點又便宜。代價很明確:幾乎沒有互動性,而且內容要改就得重新 build、重新部署。ISR 是針對這個代價的直接修補——給頁面一個 TTL,請求進來時若已經過期,就回資料源重新產生、替換 CDN 上的快取。這讓內容能動態更新,但作者馬上踩住:它仍然撐不起真正的互動。

AI 補充投影片上的流程圖比口述精確,值得把差別講清楚。SSG 的產生時機是 **build 時**,所以頁面數量會直接變成 build 時間,一萬篇文章就是一萬次渲染;ISR 則把產生時機移到 **第一個過期後的請求**,build 因此變快,代價是有人會踩到那次重新產生。實務上還有一個作者沒提的重點:ISR 通常是「先給舊的、背景更新」,也就是踩到過期的那位使用者拿到的仍然是舊頁面,新的那份要下一位才看得到——這解釋了為什麼「我改了資料庫但頁面沒變」是 ISR 最常見的困惑。另外要注意,這一整套的前提是**內容不因人而異**。一旦頁面要顯示「你好,某某某」,快取就沒辦法共用,SSG 與 ISR 都失去意義,這正是下一站必須存在的原因。

SSG

靜態網站生成

在 build 階段就把頁面渲染成靜態 HTML,之後直接由 CDN 提供。

它是三種渲染策略裡最便宜也最好擴展的:沒有伺服器運算,流量再大也只是 CDN 的事。適用條件很明確——內容對所有人都一樣,而且更新頻率低於部署頻率。它的天花板是 build 時間:頁面數量成千上萬時,一次全量 build 可能要跑幾十分鐘,這正是 ISR 出現的原因。

相關術語: ISR (它的演化)、CDN (配送方式)

出處:第 6 段「SSG 與 ISR:回到伺服器產頁面」

ISR

增量靜態再生成

靜態頁面帶有存活時間,過期後由請求觸發在伺服器端重新產生並替換快取。

它把 SSG 的「全部在 build 時做完」改成「用到才做、過期才更新」,於是 build 時間不再隨頁面數線性成長,內容也能在不重新部署的情況下更新。要注意典型實作是「先回舊的、背景重新產生」,所以觸發更新的那位使用者看到的仍是舊內容。它適合內容會變但不需要即時、且對所有人相同的頁面,例如商品頁與部落格。

相關術語: SSG (改良自)、TTL (觸發依據)

出處:第 6 段「SSG 與 ISR:回到伺服器產頁面」

CDN

內容傳遞網路

分散在各地的節點,把靜態資源快取在離使用者最近的地方。

它讓靜態資產的擴展變成幾乎不用思考的事——沒有伺服器要擴、沒有連線數要管。也因此,「這個架構有多少東西能丟上 CDN」直接決定了它的擴展性評分,這正是作者後面說 SSR 反而比純客戶端渲染難擴展的原因。

相關術語: SSG (承載對象)

出處:第 6 段「SSG 與 ISR:回到伺服器產頁面」

TTL

存活時間

一份快取資料被視為新鮮的時間長度,過期後需要重新取得或重新產生。

它是所有快取策略的旋鈕:訂得長,命中率高但資料舊;訂得短,資料新但源站壓力大。實務上常搭配 stale-while-revalidate 的想法——過期後先回舊的、同時在背景更新,兼顧速度與新鮮度,ISR 本質上就是這個模式的頁面版。

相關術語: ISR (其參數)

出處:第 6 段「SSG 與 ISR:回到伺服器產頁面」

meta framework

元框架

架在 React、Vue 這類函式庫之上,統一處理路由、資料抓取與渲染策略的框架。

Next.js、Nuxt、Astro、SvelteKit 都屬於這一類。它們存在的理由正是這一段講的內容:SSG、ISR、SSR、串流、快取這些能力單靠渲染函式庫做不到,需要一個同時掌管 build 與伺服器的層級。代價是意見很強——目錄結構、資料抓取方式、部署形態都被規定好,這也是作者後面說「跟著框架的意見走,九成九夠用」的背景。

相關術語: SSG (提供該能力)

出處:第 6 段「SSG 與 ISR:回到伺服器產頁面」

留給下一段 SSG 與 ISR 解決了速度與 SEO,但它們的前提是頁面對所有人都一樣。那需要個人化、需要真互動的頁面怎麼辦?

7. SSR、hydration 與 React Server Components 9:43–12:05

SSR 把同一套 JavaScript 框架搬到伺服器跑,先產出帶有初始狀態的 HTML 送給瀏覽器,使用者不再面對空白頁。但要讓那頁真的能互動,還得下載 bundle、跑起框架、建出 virtual DOM,再把它接到已經存在的 HTML 上——這就是 hydration。結果是「看得到很快、能點還是很慢」,中間那段時間使用者按了按鈕沒反應。演化的最後一站是 React Server Components:把元件樹上沒有互動的部分留在伺服器,只把真正需要互動的那部分送到瀏覽器,送出的 JavaScript 大幅減少,可互動的時間點也提前。作者順帶提到同一哲學下的 island architecture,但認為能講清楚 RSC 就夠用了。

SSR 在伺服器預先產生 HTML 的流程
10:00 · SSR 在伺服器預先產生 HTML 的流程
hydration:預渲染的 HTML 與下載後的元件結構接在一起
10:40 · hydration:預渲染的 HTML 與下載後的元件結構接在一起
RSC 把伺服器端元件樹裁掉,只送需要互動的那部分
11:30 · RSC 把伺服器端元件樹裁掉,只送需要互動的那部分
承上 承上:SSG 與 ISR 的前提是頁面對所有人一樣,這一段處理的正是需要個人化與真互動的那一半。

推理SSR 的作法是把同一套框架搬到伺服器跑,先產出帶有初始狀態的 HTML 送給瀏覽器,使用者不再面對空白頁。但作者立刻指出故事沒完:要讓那頁真的能點,還得下載 bundle、執行框架、建出 virtual DOM,再把它接到已經存在的 HTML 上——這就是 hydration。投影片上的時間軸把代價畫得很清楚:先是渲染伺服器產生的 HTML、達到首次內容繪製,接著才下載與執行 JavaScript,最後才 hydrate、才真的可互動。結果就是「看得到很快、能點還是很慢」,中間那段時間使用者按了按鈕不會有反應。演化的最後一站因此是 React Server Components:把元件樹上沒有互動的部分留在伺服器,只送真正需要互動的那個子集到瀏覽器——投影片上兩棵樹的對比正是這件事,伺服器那棵完整,客戶端那棵小很多。送出的 JavaScript 少了,可互動的時間點自然提前。他順帶提到同一哲學的 island architecture,但認為能講清楚 RSC 就夠用了。

AI 補充這一段的因果鏈可以再收緊一句:**hydration 是為了修補「HTML 沒有帶著行為」這個先天缺陷而存在的**。伺服器送過來的是死的字串,事件監聽器、狀態、元件對應關係全都不在裡面,所以客戶端必須重跑一次同樣的渲染,才能把行為對回去——這就是為什麼那份 JavaScript 躲不掉,也是為什麼 RSC 的思路是「一開始就別讓那些元件進入客戶端的樹」。另外有兩個實務上很痛、作者沒提的點。第一是 **hydration mismatch**:伺服器與客戶端渲染出的結果必須一致,任何依賴時間、隨機值或 window 的程式碼都會讓兩邊對不上,React 會警告甚至整段重畫。第二是 RSC 的真正代價不在效能而在心智模型:同一個檔案裡有些程式碼在伺服器跑、有些在瀏覽器跑,邊界由 `use client` 這類指示決定,跨界只能傳可序列化的資料——投影片自己也把這點寫成「更快的互動,但更高的心智模型複雜度」。

SSR

伺服器端渲染

在每次請求時於伺服器執行前端框架、產生帶有資料的 HTML 再送給瀏覽器。

跟 SSG 的差別是產生的時機:SSG 在 build 時、對所有人一樣,SSR 在請求時、可以因人而異,所以個人化內容只能靠它。代價是每個請求都要花伺服器的運算,也因此無法像靜態檔案那樣單純靠 CDN 擴展,而且首位元組時間會被伺服器的資料抓取拖慢。

相關術語: hydration (後續必要步驟)、SSG (對照組)

出處:第 7 段「SSR、hydration 與 React Server Components」

hydration

注水

在瀏覽器重新執行元件邏輯,把事件與狀態接回伺服器送來的既有 HTML 的過程。

它存在的原因是 HTML 只帶結構、不帶行為。客戶端必須重跑一次渲染來建立元件對應關係,才能掛上事件監聽器。這造成兩個常見問題:可互動時間被延後(畫面看得到但點不動),以及 hydration mismatch——兩邊渲染結果不一致時會警告甚至整段重畫,通常肇因於用了時間、隨機值或只有瀏覽器才有的 API。漸進式與選擇性 hydration 就是為了縮短這段空窗而生的。

相關術語: SSR (其後半段)、virtual DOM (過程中建立)

出處:第 7 段「SSR、hydration 與 React Server Components」

virtual DOM

虛擬 DOM

在記憶體中以物件描述畫面結構,比對前後差異後才動真正的 DOM。

它的目的不是「比較快」,而是讓開發者能用宣告式的方式描述畫面——你只要說現在該長什麼樣,差異計算交給框架。代價是每次更新都要建立與比對一整棵樹的物件,這也是為什麼 Svelte、Solid 這類編譯期方案選擇不要它。在 hydration 的脈絡裡,它是客戶端「重新認識」伺服器送來那份 HTML 的中介。

相關術語: hydration (其產物)

出處:第 7 段「SSR、hydration 與 React Server Components」

React Server Components

React 伺服器元件

只在伺服器執行、渲染結果以序列化格式送到客戶端,本身程式碼不進 bundle 的 React 元件。

它與 SSR 的差別很關鍵:SSR 把元件先在伺服器渲染成 HTML,但那個元件的 JavaScript 仍然要送到瀏覽器做 hydration;RSC 的程式碼根本不會被送出去,所以它可以直接讀資料庫、用重量級的解析套件,完全不影響 bundle 大小。代價是它不能有狀態或事件處理,開發者必須明確劃出客戶端邊界,跨界只能傳可序列化的資料。

相關術語: hydration (減少其工作量)、island architecture (同一哲學)

出處:第 7 段「SSR、hydration 與 React Server Components」

island architecture

孤島架構

頁面預設是靜態 HTML,只有少數需要互動的區塊各自獨立載入並啟用 JavaScript。

Astro 是最典型的實作。它與 RSC 的目標一致——只送必要的 JavaScript——但手段相反:孤島是「預設全靜態,例外才互動」,RSC 是在同一棵元件樹裡劃分伺服器與客戶端。孤島的每一塊可以獨立 hydrate,甚至可以用不同框架寫,適合以內容為主、互動點零星的網站。

相關術語: React Server Components (同一哲學)

出處:第 7 段「SSR、hydration 與 React Server Components」

留給下一段 這一整條渲染演化把效能推到極致,但每一步都在加東西。那總帳算下來,代價是什麼?

8. 渲染策略的代價與過早遷移的警告 12:05–13:23

作者為這一整條渲染演化算總帳:這是目前已知效能最好的建構方式,SEO 好、載入快,但擴展性反而比純客戶端渲染差——純靜態資產丟 CDN 極易擴展,一旦有伺服器端的預渲染工作,基礎設施就更複雜也更貴。複雜度極高、新人難上手、對框架的意見高度依賴,版本一改就得跟著調整。他因此給出明確的警告:只有在效能真的是產品瓶頸時才走這條路(例如電商),他知道不少公司過早搬到 Next.js,現在正在往回退。

SSR/RSC 這一整套在六軸上的位置:效能與產品價值高,但擴展性與成本都付出代價
12:25 · SSR/RSC 這一整套在六軸上的位置:效能與產品價值高,但擴展性與成本都付出代價
承上 承上:渲染演化把效能推到極致,這一段替這一整套算總帳。

推理作者的結論是:這是目前已知效能最好的建構方式,SEO 好、載入快。但接著他做了一個違反直覺、也最有價值的判斷——擴展性反而比純客戶端渲染**差**。理由很乾淨:純靜態資產丟 CDN 極易擴展,一旦有伺服器端的預渲染工作,就需要更複雜也更貴的基礎設施。複雜度他直接評成極高:技術越多,要懂的越多,新人越難上手,而且對框架的意見高度依賴,版本一改就得跟著調整。所以他的建議是條件式的:只有在效能真的是產品瓶頸時才走這條路,例如電商。他還加了一句很有份量的觀察——他知道不少公司過早搬到 Next.js,現在正在往回退。

AI 補充「效能最好但擴展性最差」這個看似矛盾的判斷,關鍵在於這兩個詞量的不是同一件事。**效能**量的是單一使用者感受到的速度,**擴展性**量的是流量成長時成本與複雜度的增加曲線。靜態檔案的曲線幾乎是水平的;每個請求都要跑一次 React 的伺服器,曲線就是斜的。理解這個區分,後面每一張六軸卡片才讀得懂。至於「過早遷移」這個現象,值得補上它的成本結構:搬到 SSR 之後,你多了一個必須維運的 Node 執行環境、一組新的錯誤類型(伺服器與客戶端狀態不一致、只在伺服器端爆掉的第三方套件)、以及一份跟框架版本綁死的部署方式。這些成本在 demo 階段完全看不到,卻會持續支付。判斷是否該搬的問法應該是:目前的載入速度真的在傷害轉換率或搜尋排名嗎?有數據嗎?

留給下一段 渲染這條線走到底了,但 SPA 內部本身從頭到尾沒有變過。當它自己大到難以維護時,該怎麼辦?

9. 模組化前端單體:先畫出邊界 13:23–14:28

前面談的都是讓 SPA 變快,但 SPA 內部本身沒有變。當它大到某個程度——作者舉的例子是三百個開發者貢獻同一份 code base——維持品質與持續出貨就變得極難。做法是在模組之間加上邊界:把共用 UI 與邏輯(design system、全域 CSS、可重用 hook)與共用服務(資料抓取、logging、analytics)抽出來,交給平台團隊維護;實際做功能的人則分進領域團隊,user 歸 user、payments 歸 payments,資料夾結構也跟著這樣切。

平台團隊的共用層與各領域團隊的模組邊界
13:50 · 平台團隊的共用層與各領域團隊的模組邊界
承上 承上:前面所有努力都在讓 SPA 變快,但 SPA 內部的結構完全沒動過,這一段處理的正是它自己長太大的問題。

推理作者先給規模感:他做過三百個開發者貢獻同一份 code base 的專案,在那個尺度下維持品質、又不讓人互相弄壞東西,極其困難。解法是在模組之間加上邊界,而他切的方式是兩層。橫的一層是共用:共用 UI 與邏輯(design system、全域 CSS、hooks、驗證)與共用服務(auth、資料抓取、logging、analytics),由平台團隊擁有與維護。直的一層是領域:user 歸 user、payments 歸 payments、billing 歸 billing,做功能的人分在領域團隊裡,資料夾結構也照著這樣切。他形容這是在大型單體裡「很快地放進一些秩序」的方法。

AI 補充這個切法之所以有效,是因為它同時解決了技術與組織兩個問題,而作者只講了技術那一半。組織那一半是:平台團隊與領域團隊的分工,其實是把「誰有權改什麼」寫進了目錄結構。共用層改動的爆炸半徑是全公司,所以需要一組專責的人與更嚴格的流程;領域內的改動只影響自己,可以放手做。這也意味著平台團隊的產出必須被當成產品來經營——有版本、有文件、有淘汰策略,否則它會退化成「沒人敢動的那個資料夾」。另外要提醒一個常見誤解:畫在圖上的邊界和程式碼裡真正的邊界是兩回事,作者稍後自己也會承認這一點。

術語:modular monolithdomain-driven design

modular monolith

模組化單體

仍然是單一部署單元,但內部依領域切成有明確邊界的模組。

它是單體與微服務之間的中間態,而且往往是最務實的一站:保留了單體的簡單(一次部署、一份設定、可以直接呼叫)與型別安全的跨模組重構,同時取得團隊各自負責的清晰界線。它也是通往拆分的合理準備——邊界如果在單體裡就守不住,拆成獨立部署只會讓問題更難修。

相關術語: platform team (維護其共用層)、micro-frontend (下一步演化)

出處:第 9 段「模組化前端單體:先畫出邊界」

platform team

平台團隊

負責建立與維護共用能力,讓產品團隊能自助使用的內部團隊。

在前端,它的產出通常是 design system、共用 hooks、資料抓取層、認證、觀測性與 build 工具。判斷它健不健康的標準是自助程度:產品團隊需不需要開票等它?它的常見失敗模式有兩種——變成幫所有人寫功能的外包團隊,或蓋出沒人想用的東西。把共用層當成有版本、有文件、有使用者的內部產品來經營,是避開這兩種失敗的通則。

相關術語: modular monolith (其運作場景)

出處:第 9 段「模組化前端單體:先畫出邊界」

domain-driven design

領域驅動設計

依業務領域而非技術層次來切分程式碼與團隊的設計方法。

它最實用的一條主張是:邊界應該畫在業務概念的接縫上,而不是畫在「所有 component 放一起、所有 hook 放一起」這種技術分類上。原因是需求變動幾乎總是沿著業務概念發生——「改付款流程」會同時碰到付款的畫面、狀態與 API,如果它們散在三個技術資料夾裡,每次改動都要跨越整個專案。它另一個常被忽略的貢獻是統一語言:程式碼裡的命名要跟業務方講的詞一致。

相關術語: modular monolith (其切分依據)

出處:第 9 段「模組化前端單體:先畫出邊界」

留給下一段 邊界要怎麼畫才對?這時候很自然會想去借經典軟體架構的成熟答案。

10. clean architecture 在前端值不值得 14:28–17:55

要實作模組邊界,可以借經典軟體架構的想法,最常見的是 clean architecture。作者用 React 舉例:把最通用的實體(user、product)抽成 domain,往外是 use case 與 repository,最外層才是 framework 與 infrastructure,所以理論上可以把 React 元件換成 Vue 或 Angular 而不動其他程式碼。但他接著自問自答:前端真的用得上嗎?短答是「有時候」。因為前端框架本身就很有意見、自帶結構,前端通常比較薄,也不像後端有那麼多邏輯;而「可以換框架」這個好處,在多數專案的生命週期裡根本用不到,投資那些抽象往往就是過度設計。他的界線是:只有非常大、或確定會活十五年的專案才值得。hexagonal 與 onion architecture 同理——概念是同一個洋蔥,最穩定的商業領域在中心,但重心都在後端。實務上跟著 Next.js 這類框架的意見走,九成九的情況就夠了。回到單體本身:擴展性跟 SPA 一樣、團隊可以更大,但代價是全域狀態、極長的 build 時間,以及最難的一點——邊界很容易畫,卻很難真的被遵守。

clean architecture 的分層在 React 程式碼裡實際長什麼樣
15:15 · clean architecture 的分層在 React 程式碼裡實際長什麼樣
投影片直接列出「為什麼經典架構不適用於前端」的四個理由
16:40 · 投影片直接列出「為什麼經典架構不適用於前端」的四個理由
模組化單體的六軸評分與它的痛點
17:35 · 模組化單體的六軸評分與它的痛點
承上 承上:邊界要怎麼畫,最自然的作法是去借經典軟體架構已經成熟的答案。

推理作者先老實示範這條路怎麼走:clean architecture 的想法是把最通用的實體(user、product)抽成 domain,往外是 use case 與 repository,最外層才是 framework 與 infrastructure,依賴永遠由外往內。投影片上的 React 範例把這四層寫在同一個檔案裡,箭頭一路往上指向 domain,而最漂亮的地方是——最下面那段 React 元件可以整段換成 Vue 或 Angular,其他程式碼一行都不用動。但他接著自問自答,而且答得很不客氣:前端真的用得上嗎?短答是「有時候」。投影片直接列出四個理由:前端框架本身就很有意見、自帶結構;前端通常是薄的,加更多結構只是額外負擔;只有在真的要換框架、需要穩定的商業邏輯時才有用;而它最大的價值其實是幫你思考怎麼解耦。他的界線因此很具體:只有非常大、或確定會活十五年的專案才值得投資這些抽象,否則就是過度設計。hexagonal 與 onion architecture 同理——本質上都是同一顆洋蔥,最穩定的商業領域在中心,但重心都在後端。實務上跟著 Next.js 這類框架的意見走,九成九的情況就夠了。最後他回到單體本身算帳:擴展性跟 SPA 相當、團隊可以更大,但代價是全域狀態、極長的 build 時間,以及最難的一點——邊界很容易畫在圖上,卻很難真的被遵守,實際上相依會長得到處都是。

AI 補充「可以整段換掉 React」這個賣點需要用力打折,因為它是這類架構最常被高估的地方。在後端,UI 只是眾多入口之一,抽掉框架後核心邏輯仍然佔大部分程式碼;但在前端,**框架相關的程式碼本身就是絕大多數**——元件結構、狀態管理、表單、路由、動畫、無障礙處理,這些全都在最外層。所以就算你完美遵守分層,換框架時要重寫的仍然是八成的程式碼,被保住的那份純邏輯往往只是幾個計算函式。這也是為什麼作者說它更像「心智練習」而不是投資。真正值得從中保留的是那條依賴方向的規則:**讓不穩定的東西依賴穩定的東西,不要反過來**。這條規則不需要整套分層就能實踐——例如不要讓資料抓取的細節滲進元件、不要讓 API 的回應形狀直接當成畫面的狀態形狀。至於他最後那句「邊界很難被遵守」,其實有工程解法可以補:用 lint 規則或 build 設定把跨領域的匯入直接擋掉,讓違規在 CI 就失敗,而不是靠自律。

術語:hexagonal architecturerepository patterndependency inversion

clean architecture

整潔架構

把系統分成同心圓,依賴只能由外向內指,核心的業務規則不知道外層的存在。

由內而外通常是 entities、use cases、interface adapters、frameworks and drivers。它的核心不是那幾層的名字,而是依賴方向的規則:容易變的(UI、資料庫、第三方服務)依賴不容易變的(業務規則),而不是反過來。在後端這筆交易很划算,在前端則要衡量——因為前端最大的一塊程式碼恰好就在最外層。

相關術語: onion architecture (同源思想)、dependency inversion (其核心規則)

出處:第 10 段「clean architecture 在前端值不值得」

hexagonal architecture

六邊形架構

以 port 定義核心與外界的契約、以 adapter 實作各種對接方式的架構風格。

又稱 ports and adapters。它與 clean architecture 幾乎是同一件事的不同說法,只是更強調「外界有很多種」——HTTP、CLI、訊息佇列、測試替身都只是不同的 adapter,核心完全不知道自己被誰呼叫。這個特性讓測試變得非常單純:接上假的 adapter 就能測完整的業務流程。

相關術語: clean architecture (同源思想)

出處:第 10 段「clean architecture 在前端值不值得」

onion architecture

洋蔥架構

以同心圓組織程式碼,越靠近中心越穩定、越接近業務本質。

它是 clean 與 hexagonal 共同的祖型,也是最容易記住的比喻:問「這段程式碼多久會因為外部原因而改變」,答案越少的就越該放在中心。這個直覺即使不採用整套分層也很有用——它讓你在寫任何模組時都會先問一句「我依賴的東西比我穩定嗎」。

相關術語: clean architecture (其祖型)

出處:第 10 段「clean architecture 在前端值不值得」

repository pattern

倉儲模式

用一個介面隱藏資料存取的細節,呼叫端只知道「取得 user」而不知道資料從哪來。

投影片範例裡的 `UserRepo` 介面加上 `ApiRepo` 實作就是它。好處是資料來源可以替換——換成 GraphQL、換成本地快取、測試時換成假資料——而使用它的程式碼完全不動。在前端它的實用價值多半體現在測試與離線支援上,不過現代的資料抓取函式庫(React Query、SWR)其實已經在框架層提供了類似的抽象。

相關術語: dependency inversion (其應用)

出處:第 10 段「clean architecture 在前端值不值得」

dependency inversion

依賴反轉

高階模組不依賴低階模組,兩者都依賴抽象出來的介面。

它是這一整組架構的共同引擎:use case 不認識 fetch,只認識 `UserRepo` 這個介面,所以實作可以被替換而流程不變。它也是最值得單獨帶走的一條原則——即使不採用任何分層架構,光是「讓元件依賴一個資料介面,而不是直接依賴 axios」就能拿到大部分好處。

相關術語: clean architecture (其核心規則)、repository pattern (常見實作)

出處:第 10 段「clean architecture 在前端值不值得」

見仁見智 15:33
「So basically you have an application where you could entirely swap your front-end framework and you wouldn't have to change the whole thing.」
在前端要大打折扣。後端抽掉框架後核心邏輯仍佔大部分程式碼,但前端最大宗的程式碼——元件結構、狀態管理、表單、路由、動畫、無障礙處理——本來就住在最外層。即使完美分層,換框架仍要重寫絕大部分,被保住的往往只是幾個純計算函式。作者自己在幾句話後也承認這通常是過度設計。
依據: 同段稍後他自己的結論:「investing in those abstractions to make that possible it's usually just overengineering」
留給下一段 如果邊界光靠紀律守不住,那還有一種更硬的辦法——把邊界變成部署的邊界。

11. micro-frontend:企業級的最後一站 17:55–20:30

最後是 micro-frontend:把上一段畫出來的領域真的拆成獨立部署的應用,在執行時再組起來。header、footer、使用者區塊各自是獨立前端應用,一個 shell 元件負責把它們拼起來並注入共用 CSS 與共用狀態。畫面因此可以按團隊切成垂直切片,每個團隊擁有自己那一塊的前後端、各自獨立部署、全部平行進行。作者給了很硬的判準:公司有上千名工程師在同一個 client 應用上工作時才需要它;小公司走這條路是自己搬石頭砸腳,只會更慢。技術上可以用 Webpack module federation,但把多個應用在使用者落地時組起來,效能一定會有折損。他也提醒:不少小公司因為 FOMO 還是會在面試裡問,所以至少要能說清楚什麼時候該用、高層次上怎麼運作。

shell 元件把多個獨立前端應用組起來的結構
18:40 · shell 元件把多個獨立前端應用組起來的結構
把畫面按團隊切成垂直切片,每片自己擁有前後端
19:10 · 把畫面按團隊切成垂直切片,每片自己擁有前後端
micro-frontend 的六軸評分:團隊規模與產品價值極高,效能與成本付出代價
20:10 · micro-frontend 的六軸評分:團隊規模與產品價值極高,效能與成本付出代價
承上 承上:模組邊界光靠紀律守不住,這一段的作法是把它升級成無法被繞過的部署邊界。

推理作者把 micro-frontend 描述成「單頁應用遇上企業軟體」:上一段畫出來的領域被真的拆成獨立部署的應用,在使用者載入頁面時才組合起來。投影片上的結構跟模組化單體那張幾乎一樣,差別只在最外層從一個 monolith 邊框換成一個 shell——shell 持有共用 CSS 與共用狀態,再注入到各個獨立應用裡。他接著用一個電商頁面示範這在畫面上長什麼樣:商品區、購物車、推薦區分屬三個團隊,每個團隊擁有自己那一塊的前後端,各自獨立部署、全部平行進行。然後是全片最硬的判準:公司有上千名工程師在同一個 client 應用上工作時才需要它;小公司走這條路是自己搬石頭砸腳,只會更慢。六軸上它的擴展性、團隊規模、產品價值都接近滿格,但效能明顯掉下來——因為所有應用要在使用者落地時才被組起來——而複雜度與成本同樣接近滿格。技術上可以用 Webpack module federation。最後他提醒:不少小公司因為 FOMO 也會在面試裡問,所以至少要能說清楚什麼時候該用、高層次上怎麼運作。

AI 補充作者說 shell 會注入共用 CSS 與共用狀態,但沒有點出這裡藏著整個模式最大的矛盾:**共用得越多,獨立性越假**。共用狀態意味著各團隊被同一份契約綁住,改它就要協調所有人;共用 CSS 更危險,因為樣式沒有天然的隔離,一個團隊改了全域樣式可能弄壞別人的畫面。真正在生產環境活得下來的 micro-frontend,通常對共用的東西極度吝嗇:只共用設計代幣與少數版本化的元件,其餘一律各自複製一份,寧可重複也不要耦合。另外「效能會下降」值得說得更具體:每個獨立應用可能各自帶一份 React,於是同一個框架被下載好幾次;module federation 的作用正是讓它們在執行時共用同一份實例,但這要求各團隊的版本必須相容——而版本協調恰恰是這個模式想要消滅的東西。這個張力沒有乾淨的解法,只有取捨,這也正好呼應整支影片的主題。

術語:shell application

micro-frontend

微前端

把單一前端應用拆成可獨立開發與部署的多個子應用,在執行時組合成完整畫面。

它解決的是組織問題而不是技術問題:多個團隊改同一份程式碼時的協調成本。判準是團隊數量與部署節奏,不是使用者數量——這也是作者強調小公司不該用的原因。代價包括重複的相依、跨應用的狀態與路由設計、以及整體體積變大。組合的時機可以在 build 時、伺服器端或執行時,三者的取捨各不相同。

相關術語: shell application (組合者)、module federation (常見實作)

出處:第 11 段「micro-frontend:企業級的最後一站」

shell application

殼層應用

負責載入、擺放各個子應用,並提供共用樣式與跨應用狀態的容器應用。

它是整個系統唯一的中心點,因此也是最容易變成瓶頸的地方:它持有的每一樣共用東西,都是所有團隊必須協調的契約。實務上的健康作法是讓它盡量薄——只管路由、掛載與少量設計代幣,把商業邏輯完全留在子應用裡。

相關術語: micro-frontend (組合對象)

出處:第 11 段「micro-frontend:企業級的最後一站」

module federation

模組聯邦

Webpack 提供的機制,讓一個應用在執行時載入另一個獨立部署應用匯出的模組。

它解決的核心問題是相依重複:沒有它,五個子應用就是五份 React。它讓宿主與遠端宣告哪些套件可以共用同一份實例,但代價是版本必須相容——而版本協調正是這個架構想要消滅的東西。這個張力沒有乾淨解法,只能在「各自帶一份、彼此完全獨立」與「共用一份、必須協調」之間選。

相關術語: micro-frontend (實作技術)

出處:第 11 段「micro-frontend:企業級的最後一站」

vertical slice

垂直切片

一個團隊完整擁有某個功能從畫面到資料的整條路徑,而不是只負責其中一層。

它跟依技術分層的組織方式(前端團隊、後端團隊、資料庫團隊)恰好相反。好處是一個需求可以由一個團隊獨立完成,不必跨團隊排程;代價是每個團隊都需要全端能力,而且跨切片的共用容易被重複實作。這正是前面 BFF 那一段說「前端工程師被推向全端」的組織版本。

相關術語: micro-frontend (其組織形態)

出處:第 11 段「micro-frontend:企業級的最後一站」

留給下一段 六站走完了,但知道有哪些架構跟能在面試裡講清楚自己的架構是兩回事。最後需要一個把這些變成自己的東西的動作。

12. 架構稽核與資深的回答長什麼樣 20:30–22:33

收尾是一份可以直接照做的架構稽核:坐下來研究自己現在的 code base,回答三個問題——目前是什麼架構風格?為什麼會走到這裡?下一個自然的步驟是什麼?把你正在用的模式全部寫下來,對照影片那張演化全圖。接著是回報方式的升級:面試被問到手上的專案時,不要停在「我們就是用 React 跟 Next.js」,而要說成「靜態頁面走 SSG,個人化的部分用 SSR,repo 結構是模組化單體,隨著規模成長我們有評估過未來走 micro-frontend」。他把答不出這種話的後果命名為 back-end rejection:面試當下一切都好,幾天後收到一封「我們找到更有經驗的人」的罐頭信——不是你做錯了什麼,而是你沒有做夠對的事。

架構稽核的四個問題,可以照著逐條回答
21:05 · 架構稽核的四個問題,可以照著逐條回答
資深版回答的實際句型
21:30 · 資深版回答的實際句型
承上 承上:六站都走完了,但知道有哪些架構跟能講清楚自己的架構是兩回事,這一段給的正是把前者變成後者的動作。

推理作者把整支影片收成一份可以立刻執行的稽核:坐下來研究自己現在的 code base,回答投影片上那幾個問題——目前是什麼架構風格?為什麼會走到這裡?自然的下一步是什麼?還用到了哪些其他模式,BFF?MVC?SSR?全部寫下來,對照影片走過的這一整排。接著是回報方式的升級,他直接給出前後對照:從「對啊,我們就是用 React 跟 Next.js」,變成「我們透過 SSG 提供靜態頁面,用 SSR 處理個人化,repo 結構做成模組化單體,隨著規模成長我們也評估過未來走向 micro-frontend」。最後他替失敗的情況取了名字——back-end rejection:面試當下一切都好,幾天後收到一封「我們找到更有經驗的人」的罐頭信。他的判斷是:那不是因為你做錯了什麼,而是因為你沒有做夠對的事。

AI 補充那句範例回答之所以有效,值得拆開來看,因為它可以直接被套用:它在一句話裡回答了三個不同層次的問題——**渲染策略**(SSG 加 SSR)、**程式碼組織**(模組化單體)、**演化方向**(考慮過 micro-frontend)。這正好對應這支影片的兩條主線加上一個時間維度,也正好是面試官想確認的三件事:你知道你在哪、你知道為什麼在這、你知道下一步。要讓這句話真的可信,還缺一樣東西作者沒提:**理由**。更強的版本會補上取捨,例如「用 SSG 是因為商品頁要 SEO,個人化的部分才用 SSR,因為我們不想放棄 CDN 快取」。有了理由,這句話才從背下來的清單變成你自己的決策。至於 back-end rejection 這個命名,它其實描述的是一個更普遍的現象:面試的淘汰理由通常不會被告知,所以你不會從結果學到任何東西——這也正是為什麼要事先把自己的架構故事準備好,而不是等被拒絕後才猜原因。

back-end rejection

後台淘汰

面試過程中一切順利,事後卻收到沒有具體理由的制式拒絕信。

作者用這個詞指出一個學不到東西的困境:淘汰的真正理由發生在你看不到的地方,回饋是通用罐頭句,所以下一次你仍然會犯同樣的錯。唯一的對策是事前把「我可能被扣分的地方」自己補齊——能說出取捨、能說出自己專案的架構故事、能說出下一步——而不是等結果出來再回頭猜。

相關術語: modular monolith (答案常包含)

出處:第 12 段「架構稽核與資深的回答長什麼樣」

留給下一段 總結收束。

4. 總結

整支影片的主張是:架構沒有好壞,只有在特定條件下比較不痛的選擇,而資深與否就看你能不能把這些條件說出來。它用一條因果鏈把所有架構串起來——每一站都是為了解決上一站的痛點而生,而每個解法又製造出下一站的問題。靜態頁面快但零互動,於是 MVC 把邏輯搬上伺服器;MVC 整頁重載又前後端緊耦合,於是 SPA 把邏輯搬進瀏覽器,也順便創造了「前端工程師」這個職位;SPA 送出太多 JavaScript、首屏空白,於是 SSG 與 ISR 把渲染搬回 build 時,但它們的前提是頁面對所有人一樣,需要個人化就得靠 SSR;SSR 又製造出 hydration 的空窗——看得到卻點不動——於是 React Server Components 只把需要互動的那部分送到瀏覽器。同一時間另一條線在跑:客戶端變多,後端被 BFF 切開,前端工程師被推向全端;SPA 自己變大,切成模組化單體,由平台團隊守共用層、領域團隊做功能;團隊再變大,邊界靠紀律守不住,才升級成部署邊界,也就是 micro-frontend。作者一路往回踩煞車:clean architecture 在前端多半是過度設計,因為前端最大宗的程式碼本來就住在最外層;Next.js 不要在效能還不是瓶頸時就搬;小公司做 micro-frontend 只會更慢。最後他把整條鏈折成一個可執行的動作——稽核自己的 code base,寫下你在哪一站、為什麼在這、下一步是哪裡,並把面試回答從「我們用 React」升級成一句同時涵蓋渲染策略、repo 結構與演化方向的話。

勘誤總整理

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

段落原話(transcript 逐字)說明
3. SPA:邏輯搬到瀏覽器那一刻
4:18
「And because you get this initial empty page, you also have very poor SEO.」在今天要打折扣。Google 等主流搜尋引擎已經會執行 JavaScript 後再索引,純 SPA 不等於搜不到。但執行有排程延遲、內容更新反映得慢,而且社群平台產生分享預覽時多半只讀初始 HTML 的 meta 標籤、完全不跑 JavaScript。所以結論仍然成立,理由要改成「慢且不可靠」,而不是「搜不到」。
依據: Google Search Central 文件說明 JavaScript 網站的兩階段索引(crawl → render queue → index)
10. clean architecture 在前端值不值得
15:33
「So basically you have an application where you could entirely swap your front-end framework and you wouldn't have to change the whole thing.」在前端要大打折扣。後端抽掉框架後核心邏輯仍佔大部分程式碼,但前端最大宗的程式碼——元件結構、狀態管理、表單、路由、動畫、無障礙處理——本來就住在最外層。即使完美分層,換框架仍要重寫絕大部分,被保住的往往只是幾個純計算函式。作者自己在幾句話後也承認這通常是過度設計。
依據: 同段稍後他自己的結論:「investing in those abstractions to make that possible it's usually just overengineering」

5. 推薦三個下一步

1. 往下挖深:micro-frontend 的實際組裝方式

影片承認只講到高層次,但真正的難處全在細節——共用相依怎麼避免被下載五次、跨應用的狀態與路由怎麼設計、樣式怎麼隔離。作者自己也說他可以另外做一支,這個缺口值得自己補上。

YouTube 搜尋:Webpack module federation micro frontend tutorial micro frontend shared state routing patterns single-spa vs module federation

2. 往旁邊對照:質疑 SPA 與重新回到伺服器的聲音

影片把演化講成一條單向前進的線,但實務上有一整派人主張多數網站根本不需要 SPA。聽過 HTMX、Astro 這類「少一點 JavaScript」的論述,才能判斷你的專案是不是被預設值推著走。

YouTube 搜尋:HTMX vs React when you don't need a SPA islands architecture Astro explained the cost of hydration resumability Qwik

3. 往上應用:實際做一次架構稽核並量化現況

影片最後那份稽核只有三個問題,但要回答「下一步是什麼」需要數據支撐——目前的 bundle 有多大、載入指標落在哪、build 要跑多久。把這些量出來,稽核才會從自述變成論證。

YouTube 搜尋:bundle analyzer webpack vite tutorial Core Web Vitals LCP INP measure real users architecture decision record ADR frontend

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