最近,Remix團隊的暴躁老哥「Ryan Florence」一連懟了好幾個友商框架,比如:



當然,這些推文發出不到一天就被老哥刪了 🤫 。
我們今天不聊以上這些事兒的對錯。
我想問問「不常關注前端新輪子發展的同學」,此時你們的內心活動是不是:
這TM都是些啥框架?我咋一個都不認識?
今天,我們從被「Ryan」吐槽的Astro的理念 —— Islands Architecture出發,來看看前端到底有多卷。
Islands Architecture是什麼Islands Architecture(孤島架構)的概念最初是由「Etsy」的前端架構師 「Katie Sylor-Miller」 在 2019 年提出,並由Preact作者「Jason Miller」在islands-architecture[1]一文中推廣。
這是一套基於SSR(服務端渲染)的架構。要了解他的特點,我們需要先了解傳統SSR的缺陷。
在傳統SSR中,首屏渲染時,服務端會向瀏覽器輸出HTML結構。
當瀏覽器渲染HTML後,再執行前端框架的初始化邏輯,為HTML結構綁定事件,這一步叫hydrate(注水)。
當hydrate完成後,頁面才能響應用戶交互。
也就是說,只有當整個頁面所有組件hydrate完成後,頁面中任一組件才能響應用戶交互。
Chrome LightHouse跑分中的TTI[2](Time to Interactive,可交互時間)指標用于衡量「頁面變得完全可交互所需的時間」。

傳統SSR架構的頁面隨着應用體積變大,TTI指標會持續走高。
孤島架構的目的就是為了優化SSR架構下TTI指標的問題。
在孤島架構架構下,組件分為:
交互組件
首屏不可交互組件
比如在如下頁面結構中:

「首屏不可交互組件」包括Content、Advertisement、Footer(白色部分)
「交互組件」包括Header、Sliderbar、Image Carousel(彩色部分)
「首屏不可交互組件」會像傳統SSR一樣向瀏覽器輸出HTML,而「交互組件」會在瀏覽器異步、並發渲染。
「交互組件」就像HTML海洋中的孤島,因此得名孤島架構。

孤島架構可以讓「交互優先級較高的組件」優先變得可交互,剩下的低優組件再慢慢hydrate。
如此,在頁面hydrate完成前,重要的組件已經可交互了,藉此就能降低TTI指標。
孤島架構的現實意義在哪呢?比如,對於一個電商網站,顯然「立刻購買按鈕」的可交互性優先級高於「反饋按鈕」的可交互性。
SSR讓用戶能夠更早看到頁面,孤島架構讓頁面中重要的部分(立刻購買按鈕)可以更早被點擊。這背後,就是更高的購買率,更多的錢~~~
實現Islands Architecture的框架在當前,實現孤島架構的全棧框架主要是Astro與Qwik。
AstroAstro的特點是:作為全棧框架,主要把控整體架構,對實現具體業務所需前端框架沒有要求。
也就是說,開發者可以在Astro中使用React、Vue、Preact、Svelte等框架實現具體業務邏輯,甚至是在一個.astro組件中混用其他框架的組件。
比如,在下面例子中.astro組件中引入了React、Vue、Svelte三款框架的組件:

Qwik的作者是builder.io的CTO 「miško hevery」(同時也是Angular/AngularJS的發明者)。

這款框架的特點是:超細粒度的孤島架構,且粒度是開發者可控的。
對於Astro,孤島架構適用的對象是組件。而在Qwik中,孤島架構最細的粒度是「組件中的某個方法」。
舉個例子,下面是HelloWorld組件(可以發現,Qwik採用類似React的語法):

對應頁面渲染效果:

打開瀏覽器Network面板,這個頁面會有多少JS請求呢?
由於這是個靜態的組件,沒有邏輯,所以答案是:沒有JS請求。
再來看看經典的計數器Counter組件,相比HelloWorld,增加了「點擊按鈕狀態變化的邏輯」,代碼如下:

對應頁面渲染效果:

打開瀏覽器Network面板,這個頁面會有多少JS請求呢?
答案還是:沒有JS請求。
注意這兩個組件的代碼中,定義組件使用的是component$,有個$符號。
在Counter中,onClick$回調也有個$符號。
在Qwik中,後綴帶$的函數都是「懶加載」的。
孤島架構的粒度有多細,就取決於$定義的多細。
比如在Counter中,onClick$帶$後綴,那麼點擊回調是懶加載的,所以首屏渲染不會包含「點擊後的邏輯」對應的JS代碼。
在點擊按鈕後,會發起2個JS請求,第一個請求返回的是「點擊後的邏輯」:

第2個JS請求返回的是「組件重新render的邏輯」:

這兩段代碼執行後,Counter變為1。

審查元素會發現,點擊前,button on:click屬性中保存了「邏輯所在的地址」:

點擊後,會從對應地址下載JS代碼,執行對應邏輯。
React為什麼文章開頭暴躁老哥吐槽Astro、Qwik沒有什麼新鮮理念呢,這是因為React很早就在朝着孤島架構的理念發展了。
在React中,這套理念被稱為Selective Hydration[3]。
具體來說,在SSR場景下,被Suspense組件包裹的組件會作為孤島架構下的「交互組件」。
前端有多卷雖然孤島架構下的全棧框架有眾多好處(首屏渲染快、TTI短),但並不是萬能的。
他比較適合「對首屏渲染速度、TTI要求高,但整體頁面交互不複雜」的場景,比如:
電商頁面
博客
文檔
對於「重交互性」的Web應用(比如「後台管理系統」、「社區」),更適合傳統的SSR方案(比如Next.js)或CSR方案(直接使用前端框架)。
可見,孤島架構的應用場景並不大,但他的實現難度卻比CSR或傳統SSR高得多。
大部分開發者,究其一生可能都不會用到孤島架構。
就是這么小的細分領域,都湧現了這麼多競爭對手。
前端,真是太卷了......
參考資料islands-architecture: https://jasonformat.com/islands-architecture/
[2]TTI: https://web.dev/interactive/
[3]Selective Hydration: https://github.com/reactwg/react-18/discussions/37