
軟體工程的歷史就是一部「痛點驅動」的演進史。每一個新工具的誕生,幾乎都是因為上一代方案有著讓人無法忍受的問題。
先講結論
很多人學技術只學「怎麼用」,卻不問「為什麼會有這個東西」。結果面對技術選型毫無判斷力——什麼火用什麼。理解了演進鏈,你就能明白每個技術「解決了什麼」和「犧牲了什麼」。這篇是系列的第一篇,講 DOM 操作和前端架構的演進。
系列文章:本篇:DOM 與架構 → 非同步、CSS 與狀態管理 → API 設計與部署
DOM 操作的演進:原生 JS → jQuery → 框架
2005 年的黑暗歲月
如果你在 2005 年寫前端,光是選取一個 class 為 “item” 的元素就要寫這種東西:
var items = [];
var allElements = document.getElementsByTagName('*');
for (var i = 0; i < allElements.length; i++) {
if (allElements[i].className === 'item') {
items.push(allElements[i]);
}
}因為 IE6 不支援 getElementsByClassName。而且每個瀏覽器的 DOM API 都不一樣——IE 用 attachEvent,其他用 addEventListener。CSS 的 opacity 在 IE 要用 filter: alpha(opacity=50)。
前端工程師的工時不是花在功能開發,而是花在「讓它在 IE6 上也能跑」。這不是工程,這是苦行。
jQuery:救世主降臨(2006)
jQuery 把所有瀏覽器差異包裝起來,提供統一 API:
$('.item').addClass('active').fadeIn(300);
$.get('/api/users', function(data) { $('#user-list').html(data); });
$('#btn').on('click', function() { $(this).toggleClass('active'); });鏈式呼叫、跨瀏覽器相容、選擇器引擎——jQuery 在鼎盛時期被 70% 以上的網站使用。它不是框架,它是基礎設施。
jQuery 的崩壞:spaghetti code
但當 Web App 變複雜,jQuery 的問題就暴露了:
$('#search-btn').on('click', function() {
$.get('/api/products?q=' + $('#search-input').val(), function(data) {
$('#product-list').empty();
data.forEach(function(product) {
$('#product-list').append('<div>' + product.name + '</div>');
});
// DOM 是新建的,事件要重新綁
$('.add-to-cart').off('click').on('click', function() {
addToCart($(this).data('id'));
updateCartCount();
// ...更多手動 DOM 操作
});
});
});資料邏輯、DOM 操作、事件處理全部攪在一起。沒有元件概念、沒有資料流、手動保持畫面和資料同步。當 App 長到一定規模,沒有人搞得清楚哪段 code 改了哪段 DOM。
框架的回應:讓 UI 和資料自動同步
2010 年代初,三個框架幾乎同時出現:
Angular(2010) 用 two-way data binding——資料改了畫面自動更新。聽起來美好,但雙向綁定在複雜應用中會導致你不知道是誰改了什麼值。
React(2013) 完全不同的思路:Virtual DOM + 單向資料流。你告訴它「畫面該長什麼樣」,它算出最小的 DOM 更新。Component 的概念讓 UI 變成可重用的積木。
Vue(2014) 走漸進式路線——學習曲線比 Angular 平緩,比 React 更接近傳統 HTML。
最終業界達成共識:Component-based architecture 是正確方向。 這個思維至今仍然主宰整個前端生態。
前端架構的演進:MPA → SPA → SSR → Islands
MPA:最初的模樣
Web 最初全是 MPA(Multi-Page Application)。點連結 → 伺服器渲染 HTML → 整頁重載。SEO 天然好、邏輯簡單。但體驗?每次操作都白閃一下,狀態丟失。
2004 年 Gmail 展示了不用整頁重載就能操作郵件的體驗,人們意識到:Web 可以像原生 App 一樣流暢。
SPA:前端的黃金年代
隨著 React/Angular 普及,SPA 爆發。整個 App 一個 HTML 頁面,路由切換和畫面更新全在客戶端,資料透過 API 取得。
使用者體驗絲滑了,但新問題來了:
- SEO 爆死:搜尋引擎看到的只有
<div id="root"></div> - 首屏白到天荒地老:使用者要先下載一大包 JS,等它跑完畫面才出來
- 所有渲染工作都推給客戶端,伺服器的算力浪費了
SSR:回到伺服器,帶著新武器
Next.js(2016)代表業界的反思:第一次請求由伺服器渲染好 HTML(解決 SEO 和首屏問題),然後客戶端 hydrate(保留 SPA 流暢體驗)。
代價?伺服器負擔增加、部署變複雜、Hydration 本身也有效能問題——瀏覽器要重新跑一遍 JS 來「啟動」已經渲染好的 HTML。
Islands:只 hydrate 需要互動的部分
Astro(2021)更激進:大部分內容保持純 HTML,只有需要互動的部分(搜尋框、動態表單)才載入 JS。一個內容網站可能只需要幾 KB 的 JS,而不是幾百 KB。
每一次架構演進,都是在效能、互動性、開發者體驗之間尋找新的平衡點。 沒有哪個方案是萬能的——選擇取決於你的產品需求。
jQuery 解決了瀏覽器不一致,React 解決了 UI 同步,Next.js 解決了 SSR。每一代都站在上一代的肩膀上——同時也創造了新的問題留給下一代。