Tom 最近發(fā)表了對現(xiàn)代 web 的“二次思考”, 在前端世界掀起了一場風暴。你應該讀讀這篇文章或者起碼讀讀摘要部分。我對于文章的很多內(nèi)容持認可觀點。
React 有很多優(yōu)勢:在現(xiàn)代交互界面...但是也有很多缺點。
對于靜態(tài)的站點而言,在客戶端運行 React 絕對是一種資源浪費。如果你的應用程序非常具有交互性,你必須避免使用 React ,這也是事實。人們普遍認為,如果你想要 60 fps 的動畫效果,你可能需要繞過 React 更新反應周期,以一種更優(yōu)雅的方式來實現(xiàn)( react-spring 就是干這事的)。但是,盡管所有這些 React 相關說法都是正確的,但在組件架構方面的觀點我則不敢茍同。
用戶會話的時間長得驚人: 我親眼所見,有人可能一次就把你的網(wǎng)站打開幾個星期。 因此,如果他們打開了“關于”頁面,保持標簽打開一周,然后請求主頁,然后他們請求的主頁由他們上周下載的索引包決定。這是一個非常奇怪和沒有得到充分討論的問題。
這是一個很好的觀點,但問題沒有真正得到解決,(正如 Tom 所承認的那樣) 它實際上只是將一個一直存在的問題進行了夸張。我認為有一些解決方案,我們可以遍歷 “index bundle” 路徑,并且可以將網(wǎng)站版本存儲在 cookie 中,然后用它來判斷版本是否匹配。但是這么做,確實會額外花費一些精力。
這是你的創(chuàng)業(yè)公司的主頁,有一個“注冊”按鈕,但是在 Java 加載之前,這個按鈕什么也做不了。所以你需要做一些補償措施。
雖然這樣做很簡單,但是這的確是一個問題。
<button class="sign-up" disabled= {!is_browser}> {is_browser ? 'Sign up' : 'Loading'} </button>
我不確定 React 風格的框架會怎么做,不管前端采用何種形式,這個問題一直都存在,除非你不用 JS。
你以前的輕量級應用程序服務器的確在承擔相當多的任務,運行 React 和發(fā)送 API 請求來完成預渲染。
事實上,React 的服務器端渲染:構建組件樹,然后序列化它—這就涉及到一些框架層面無法共享的性能開銷,如將組建編譯成拼接 SSR 字符串的函數(shù),它的運行速度就會快很多。而且這些 API 請求必不可少,所以盡早響應這些請求就很有必要,尤其是當你的應用服務器和 API 服務器地理位置很近(甚至是同一個服務器)的時候。
理想的 API 具有通用和靈活的特點,你可以基于這些接口構建任意的 web 應用程序。這個想法很快破滅。
請去多讀幾遍 整個 API 部分。
除了一些小小的吹毛求疵之外,Tom 還指出了 web 開發(fā)中的一些現(xiàn)實問題。但我認為這篇文章得出了一個危險的結論。
讓我們從剖析這個表述開始:
例如,我可以保證這個博客比任何一個 Gatsby 博客都要快(雖然我也非常喜歡 Gatsby 團隊),因為 React 靜態(tài)站點無法做到比非 React 靜態(tài)站點更快。
恕我直言,我不認為 Gatsby 適合當作基準來比較。gatsby new my-site 在生產(chǎn)模式下啟動完全靜態(tài)的頁面需要執(zhí)行 266kb 的Java 文件; gatsbyjs.org 官網(wǎng)就得加載 808 kb 的 JS 文件。說實話,這樣比沒啥意義。
這是從 webpagetest.org/easy 處獲取到的 Gatsby 首頁的 lighthouse 結果。
我并不認可這個前提。當我點擊 Tom 的不含 JS 的網(wǎng)站中的一個鏈接時,瀏覽器首先等待確認這是一個點擊,而不是一個動畫效果,然后發(fā)出請求,我們必須等待響應。如果我們使用具有客戶端路由的框架編寫網(wǎng)站,我們就可以在等待過程中做更多有趣的事情。我們可以根據(jù)用戶可能與哪些事物進行交互的分析來做出明智的猜測,并據(jù)此執(zhí)行一些預加載數(shù)據(jù)和處理。我們可以在用戶第一次觸碰到 (或者懸停) 鏈接時立即啟動請求,而不是等待點擊的確認 (最壞的情況是這樣) ,我們已經(jīng)加載了一些東西,如果他們以后真的點擊它,這些東西就可以被利用起來。我們可以提供更好的視覺反饋,即加載正在進行,過渡效果等。而且我們通常不需要加載整個頁面的內(nèi)容,我們可以使用一點點 JSON,因為我們已經(jīng)有了頁面的 Java。這東西手工做起來極其困難。
除此之外,普通的靜態(tài)網(wǎng)站并不夠優(yōu)雅。以頁面切換為例。網(wǎng)絡開發(fā)人員目前陷入了一種思維模式,即網(wǎng)頁頁面變化不和諧:點擊鏈接,無論是通過客戶端路由還是重新加載頁面,整個頁面都會被替換ー而本地應用開發(fā)人員則在另一個層面上思考:
技術進步不足以讓互聯(lián)網(wǎng)達到那個程度,還需要文化上的轉(zhuǎn)變。但是,如果我們放棄目前的軌道,我們當然不可能達到那個目標。這正是 Tom 的意思。
我不知道還有哪個平臺會要求你使用不同于后續(xù)交互邏輯的技術來編寫初始化渲染的邏輯。這個想法聽起來很愚蠢。但是在有著獨特歷史的網(wǎng)絡上,這已經(jīng)成為多年來的常態(tài)了ー我們用 PHP 或 Rails 或其他什么東西生成一些 HTML,然后在上面“撒上一些 jQuery”。
隨著 Node 的出現(xiàn),這種情況發(fā)生了改變。我們可以使用原生語言做服務器端渲染,可以與數(shù)據(jù)庫通信,發(fā)展迅猛。
這種模式存在一些問題。Tom 指出了其中一些問題。他沒有討論的另一個主要問題是,服務器渲染的 SPA (單頁面應用)模型通常會“hydrates” 整個初始頁面,這種方式要求你復制大量數(shù)據(jù)(一次是在 HTML 中,一次是在傳遞到應用程序客戶端版本的 JSON 二進制中,以產(chǎn)生完全相同的結果) ,并在用戶開始與應用程序交互期間阻塞主線程。
但是我們可以解決這些問題。Next 是圍繞(例如)在單個應用程序中混合靜態(tài)和動態(tài)頁面進行驚人的創(chuàng)新,這樣你就可以獲得純靜態(tài)模型的好處,而不會最終發(fā)現(xiàn)自己受到它的限制。Marko 進行智能組件級數(shù)據(jù)填充,我希望其他框架也能采用這種方法。Sapper 是 Svelte 開發(fā)的框架,它有一個明確的目標,即在不需要的頁面外,不需要加載除(微型)路由之外的任何 JS 文件。
我想要的未來ー我看到的未來ー是一個擁有更多人 (包括設計師) 都可以使用的工具的未來,它可以在適當?shù)那闆r下智能地在服務器和客戶機之間遷移工作,讓我們建立與用戶體驗本地化競爭的體驗。如果將網(wǎng)站的一部分升級為“交互式”或者從“靜態(tài)”升級為“動態(tài)” ,就不會涉及使用不同技術的不同團隊之間的通信。我們只能通過遵循 Tom 批評的 Java 組件框架服務器渲染的 SPA (單頁面應用模式)來實現(xiàn)這個目的。
雖然現(xiàn)代前端技術體系有缺陷,我們應該直面問題,而不是拋棄它。