如果您認(rèn)為靜態(tài)呈現(xiàn)僅限于對(duì)網(wǎng)站的每個(gè)用戶都一樣的通用公共內(nèi)容,那么您絕對(duì)應(yīng)該閱讀這篇文章。
分段呈現(xiàn)(Segmented Rendering)是Jamstack的一種新模式,它允許您靜態(tài)地個(gè)性化內(nèi)容,而不需要任何類型的客戶端呈現(xiàn)或基于請(qǐng)求的服務(wù)器端呈現(xiàn)。有許多用例:個(gè)性化、國(guó)際化、主題化、多租戶、A/B測(cè)試…
讓我們關(guān)注一個(gè)對(duì)博客所有者非常有用的場(chǎng)景:處理付費(fèi)內(nèi)容。
祝賀你找到了新工作#
哇,你剛剛升職了!你現(xiàn)在是《修補(bǔ)》雜志的“表演主管”,這是《粉碎》雜志最大的競(jìng)爭(zhēng)對(duì)手。修復(fù)雜志有一個(gè)非常奇特的商業(yè)模式。每篇文章中的詼諧段子只有付費(fèi)用戶才能看到。
程序員為什么要過馬路?
我打賭你會(huì)付錢知道答案。
您今天的任務(wù)是以最佳性能實(shí)現(xiàn)這一特性。讓我們看看你怎么做。提示:我們將引入一個(gè)名為“分段渲染”的新模式
使用現(xiàn)代Javascript框架呈現(xiàn)網(wǎng)頁的多種方式#
Next.js的流行源于其對(duì)“渲染三力”的掌握,即在一個(gè)框架中結(jié)合客戶端渲染、基于請(qǐng)求的服務(wù)器渲染和靜態(tài)渲染的能力。
南車,SSR,SSG…讓我們澄清一下他們是什么#
修復(fù)雜志用戶界面依賴于一個(gè)現(xiàn)代的Javascript庫,React。像其他類似的UI庫一樣,React提供了兩種呈現(xiàn)內(nèi)容的方式:客戶端和服務(wù)器端。
客戶端渲染(CSR)發(fā)生在用戶的瀏覽器中。在過去,我們會(huì)使用jQuery來完成CSR。
服務(wù)器端呈現(xiàn)發(fā)生在您自己的服務(wù)器上,要么在請(qǐng)求時(shí)(SSR),要么在構(gòu)建時(shí)(靜態(tài)或SSG)。SSR和SSG也存在于Javascript生態(tài)系統(tǒng)之外。例如,想想PHP或Jekyll。
讓我們看看這些模式如何應(yīng)用到我們的用例中。
CSR:丑陋的裝載機(jī)問題#
客戶端渲染(CSR)會(huì)在頁面加載后在瀏覽器中使用Javascript來添加詼諧的笑話。我們可以使用“fetch”來獲取笑話內(nèi)容,然后將它們插入DOM。
CSR涉及冗余的客戶端計(jì)算和大量難看的加載器。
這是可行的,但這是最好的方法嗎?你的服務(wù)員必須為每個(gè)讀者提供詼諧的笑話。如果有任何事情導(dǎo)致Javascript代碼失敗,付費(fèi)用戶將不會(huì)得到他們想要的樂趣,可能會(huì)生氣。如果用戶有一個(gè)緩慢的網(wǎng)絡(luò)或緩慢的計(jì)算機(jī),當(dāng)他們的笑話被下載時(shí),他們會(huì)看到一個(gè)丑陋的加載程序。請(qǐng)記住,大多數(shù)訪問者是通過移動(dòng)設(shè)備瀏覽的!
隨著API調(diào)用數(shù)量的增加,這個(gè)問題只會(huì)變得更糟。請(qǐng)記住,一個(gè)瀏覽器只能并行運(yùn)行少量請(qǐng)求(通常每個(gè)服務(wù)器/代理6個(gè)請(qǐng)求)。服務(wù)器端呈現(xiàn)不受此限制,并且在從您自己的內(nèi)部服務(wù)獲取數(shù)據(jù)時(shí)會(huì)更快。
每個(gè)請(qǐng)求的SSR:被第一個(gè)字節(jié)占用#
每請(qǐng)求服務(wù)器端呈現(xiàn)(SSR)在服務(wù)器上按需生成內(nèi)容。如果用戶付費(fèi),服務(wù)器直接以HTML的形式返回整篇文章。否則,它會(huì)返回沒有任何樂趣的乏味文章。
SSR移除了客戶端計(jì)算,但沒有移除加載時(shí)間。
我們不再依賴客戶端Javascript。然而,為每個(gè)請(qǐng)求呈現(xiàn)文章并不節(jié)能。到達(dá)第一個(gè)字節(jié)的時(shí)間(TTFB)也增加了,因?yàn)樵谖覀冮_始看到一些內(nèi)容之前,我們必須等待服務(wù)器完成它的工作。
我們已經(jīng)用更難看的空白屏幕取代了難看的客戶端加載程序!現(xiàn)在我們還要為此付出代價(jià)!
“重新驗(yàn)證時(shí)失效”緩存控制策略可以通過在頁面更新前提供緩存版本來減少TTFB問題。但對(duì)于個(gè)性化內(nèi)容,它不能開箱即用,因?yàn)樵诓豢紤]cookies的情況下,它只能緩存每個(gè)URL的一個(gè)頁面版本,并且不能處理提供付費(fèi)內(nèi)容所需的安全檢查。
靜態(tài)渲染:富客戶/窮客戶問題的關(guān)鍵#
在這一點(diǎn)上,你碰到了我稱之為“富客戶/窮客戶”的問題:你的高級(jí)用戶得到的是最差的性能,而不是最好的。
根據(jù)設(shè)計(jì),與靜態(tài)呈現(xiàn)相比,客戶端呈現(xiàn)和每請(qǐng)求服務(wù)器端呈現(xiàn)涉及最多的計(jì)算,靜態(tài)呈現(xiàn)在構(gòu)建時(shí)只發(fā)生一次。
我所知道的99%的網(wǎng)站都會(huì)選擇CSR或者SSR,并且飽受博客/窮客戶問題的困擾。
深入了解分段渲染#
分段渲染只是進(jìn)行靜態(tài)渲染的一種更聰明的方式。一旦你理解了這一切都是關(guān)于緩存渲染,然后為每個(gè)請(qǐng)求獲得正確的緩存渲染,一切都會(huì)水到渠成。
靜態(tài)渲染提供了最佳性能,但靈活性較差#
靜態(tài)站點(diǎn)生成(SSG)在構(gòu)建時(shí)生成內(nèi)容。這是性能最好的方法,因?yàn)槲覀円淮涡缘爻尸F(xiàn)了文章。然后作為純HTML提供。
這解釋了為什么構(gòu)建時(shí)預(yù)渲染是Jamstack理念的基石之一。作為新晉升的“業(yè)績(jī)負(fù)責(zé)人”,這絕對(duì)是你想要的!
截至2022年,所有Jamstack框架都有大致相同的靜態(tài)渲染方法:
- 你計(jì)算所有可能的URL的列表;
- 您為每個(gè)URL呈現(xiàn)一個(gè)頁面。
靜態(tài)渲染第一步的結(jié)果:計(jì)算一堆你要預(yù)渲染的URL。對(duì)于博客來說,它通常是你所有文章的列表。在第2步中,您只需呈現(xiàn)每篇文章,每個(gè)URL一篇。
這意味著一個(gè)URL嚴(yán)格地等于頁面的一個(gè)版本。你不能在同一個(gè)網(wǎng)址上有一篇文章的付費(fèi)和免費(fèi)版本,即使是對(duì)不同的用戶。網(wǎng)址/如何修理一個(gè)壞掉的雜志將向每個(gè)人提供相同的HTML內(nèi)容,沒有任何個(gè)性化選項(xiàng)。不可能考慮請(qǐng)求cookies。
分段呈現(xiàn)可以更進(jìn)一步,為同一URL呈現(xiàn)不同的變化。讓我們學(xué)習(xí)如何。
解耦URL和頁面變化#
允許個(gè)性化內(nèi)容的最天真的解決方案是給URL添加一個(gè)新的路由參數(shù),例如,“有笑話”對(duì)“平淡無奇”
Next.js的實(shí)現(xiàn)大致如下:
第一個(gè)函數(shù)為同一篇文章計(jì)算2個(gè)URL,一個(gè)有趣的和一個(gè)乏味的。第二個(gè)函數(shù)得到了笑話,但只針對(duì)付費(fèi)版本。
太好了,你的文章有兩個(gè)版本。我們可以開始在“分段渲染”中看到“分段”——付費(fèi)用戶和免費(fèi)用戶,每個(gè)分段有一個(gè)渲染版本。
但是現(xiàn)在,你有了一個(gè)新的問題:如何將用戶重定向到正確的頁面?簡(jiǎn)單:直接將用戶重定向到正確的頁面!有服務(wù)器什么的!
起初,您需要一個(gè)web服務(wù)器來實(shí)現(xiàn)高效的靜態(tài)渲染,這聽起來可能很奇怪。但是請(qǐng)相信我:靜態(tài)網(wǎng)站獲得最佳性能的唯一方法是做一些服務(wù)器優(yōu)化
使用免費(fèi)的axe DevTools Chrome瀏覽器擴(kuò)展,只需幾分鐘即可開始可訪問性測(cè)試。
關(guān)于“靜態(tài)”主機(jī)的說明#
如果你來自Jamstack生態(tài)系統(tǒng),你可能會(huì)愛上靜態(tài)托管。有什么感覺比推送幾個(gè)文件,讓你的網(wǎng)站在GitHub頁面上啟動(dòng)運(yùn)行更好呢?還是直接在內(nèi)容交付網(wǎng)絡(luò)(CDN)上托管成熟的應(yīng)用程序?
然而“靜態(tài)托管”并不意味著沒有服務(wù)器。這意味著你不能控制服務(wù)器。仍然有一個(gè)服務(wù)器負(fù)責(zé)將每個(gè)URL指向正確的靜態(tài)文件。
靜態(tài)托管應(yīng)該被看作是一個(gè)有限的,但廉價(jià)和高性能的選擇,以托管個(gè)人網(wǎng)站或公司登錄頁面。如果您想超越這一點(diǎn),您將需要控制服務(wù)器,至少要處理諸如基于請(qǐng)求cookies或頭的重定向之類的事情。
雖然不需要打電話給后端專家。我們不需要任何復(fù)雜的計(jì)算??梢詸z查用戶是否付費(fèi)的非?;镜闹囟ㄏ蚍?wù)器就可以了。
好消息:Vercel或Netlify等現(xiàn)代主機(jī)實(shí)現(xiàn)了邊緣處理程序,這正是我們這里需要的。Next.js將這些邊緣處理程序?qū)崿F(xiàn)為“中間件”,因此您可以用Javascript對(duì)它們進(jìn)行編碼。
“邊緣”意味著計(jì)算盡可能靠近最終用戶,而不是擁有幾個(gè)大型集中式服務(wù)器。您可以將它們視為核心基礎(chǔ)架構(gòu)的外墻。它們非常適合個(gè)性化,這通常與用戶的實(shí)際地理位置有關(guān)。
使用NEXT.JS中間件輕松重定向#
Next.js中間件非???,編碼非常簡(jiǎn)單。與AWS Gateway等云代理或Nginx等開源工具不同,中間件是用Javascript編寫的,使用Web標(biāo)準(zhǔn),即獲取API。
在“分段呈現(xiàn)”架構(gòu)中,中間件只是負(fù)責(zé)將每個(gè)用戶請(qǐng)求指向頁面的正確版本:
進(jìn)口 {NextResponse} 從 "下一個(gè)/服務(wù)器"; 進(jìn)口類型{下一個(gè)請(qǐng)求} 從 "下一個(gè)/服務(wù)器"; 異步?非同步(asynchronous) 功能 中間件(請(qǐng)求:下一個(gè)請(qǐng)求) { // isPaidFromReq可以讀取cookies,獲取身份驗(yàn)證令牌, //并驗(yàn)證用戶是否確實(shí)是付費(fèi)會(huì)員 常數(shù)isPaid= 等待 isPaidFromReq(請(qǐng)求); 常數(shù)例行程序=isPaid? “帶-笑話” : “淡而無味”; 返回NextResponse。再直接的( `/${例行程序}/如何修理一個(gè)壞掉的雜志` ); }
一個(gè)為付費(fèi)和免費(fèi)用戶實(shí)現(xiàn)分段渲染的中間件。
嗯,就是這樣。你作為“表演主管”的第一天結(jié)束了。你擁有一切你需要的東西來為你怪異的商業(yè)模式實(shí)現(xiàn)最好的表現(xiàn)!
當(dāng)然,您可以將這種模式應(yīng)用于許多其他用例:國(guó)際化內(nèi)容、A/B測(cè)試、亮/暗模式、個(gè)性化……您的頁面的每一種變化都構(gòu)成了一個(gè)新的“部分”:法國(guó)用戶、喜歡暗主題的人或付費(fèi)用戶。
頂端的櫻桃:URL重寫#
但是,嘿,你是“性能的頭”,而不是“性能的平均”!你希望你的web應(yīng)用程序是完美的,而不僅僅是好的!你的網(wǎng)站在所有指標(biāo)上都非常快,但現(xiàn)在你的文章網(wǎng)址看起來像這樣:
那真的不好看…分段渲染很棒,但是最終用戶不需要知道它自己的“分段”對(duì)優(yōu)秀工作的懲罰是更多的工作,所以讓我們添加最后一點(diǎn):不要使用URL重定向,使用URL重寫。它們是完全一樣的東西,除了你不會(huì)在URL中看到參數(shù)。
網(wǎng)址/如何縮短網(wǎng)址沒有任何路由參數(shù),現(xiàn)在將根據(jù)用戶的cookies顯示頁面的正確版本。route參數(shù)仍然“存在”在您的應(yīng)用程序中,但是最終用戶看不到它,并且URL保持干凈。完美。