0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

天貓汽車商詳頁的SSR改造實(shí)踐

OSC開源社區(qū) ? 來源:OSC開源社區(qū) ? 2023-02-03 14:54 ? 次閱讀

由于汽車業(yè)務(wù)的特殊性,天貓汽車基于 Rax 多頁應(yīng)用自建了商品詳情的 H5 頁面。自定義商詳承載了眾多業(yè)務(wù)能力和投放場景。隨著業(yè)務(wù)的發(fā)展和頁面承載內(nèi)容的增多,開始出現(xiàn)白屏?xí)r間太長等體驗(yàn)問題。

前端性能優(yōu)化算是個(gè)老生常談的問題,我們的頁面已經(jīng)做過首屏接口合并、圖片懶加載、骨架屏等體驗(yàn)優(yōu)化,想進(jìn)一步提升用戶體驗(yàn)就要從渲染機(jī)制和渲染容器入手了。從容器側(cè)看,淘寶端原生提供的 pha 容器提供的數(shù)據(jù)預(yù)請求、資源離線緩存等功能,可以有效提升手淘內(nèi)的 H5 頁面體驗(yàn)。但是其它渠道的端缺少類似容器能力,需要從渲染機(jī)制方向?qū)ふ页雎贰?/span>

SSR(Server Side Render)是相對于現(xiàn)有渲染機(jī)制CSR(Client Side Render)的一種渲染方案。在用戶通過客戶端(Client Side)請求頁面資源時(shí),CSR 拿到是一份空文檔,再通過數(shù)據(jù)請求、執(zhí)行渲染腳本后生成文檔,最后展示給用戶。而 SSR 在請求后拿到的就是服務(wù)端(Server Side)經(jīng)過數(shù)據(jù)請求腳本渲染以后的完整文檔,由于它不強(qiáng)依賴客戶端的能力,具有更加穩(wěn)定的性能和較好的用戶體驗(yàn)。

為了提升淘寶外、特別是中低端機(jī)用戶的瀏覽體驗(yàn),我們對自定義商詳進(jìn)行了 SSR 化探索,完成了 Rax 多頁應(yīng)用向 Rax 全棧應(yīng)用的改造,以下是我們的改造歷程。

代碼結(jié)構(gòu)

項(xiàng)目現(xiàn)在的 Rax 多頁應(yīng)用體系和目標(biāo)體系 Rax 全棧應(yīng)用都基于 Rax 框架,目錄結(jié)構(gòu)比較相似,全棧應(yīng)用在多頁應(yīng)用的基礎(chǔ)上增加了服務(wù)端渲染函數(shù)和FaaS相關(guān) 工程配置。Rax 多頁應(yīng)用的目錄如下:

├── src
│   ├── app.json                    # 路由及頁面配置
│   ├── components/                 # 自定義業(yè)務(wù)組件
│   ├── pages/                      # 頁面
├── build.json                      # 工程配置
├── package.json
└── tsconfig.json
Rax 全棧應(yīng)用目錄如下:
├── src
│   ├── apis                      # 函數(shù)源碼
│   │   ├── configuration.ts
│   │   ├── lambda/               # 接口
│   │   ├── render                # 渲染函數(shù)目錄                       
│   │   │   ├── home/             # 渲染函數(shù),需與 pages 里的頁面名一一對應(yīng)       
│   │   │   └── ....../  
│   │   └── typings/              # 數(shù)據(jù)類型定義
│   ├── pages                     # 頁面      
│   │       ├── home/   
│   │       └── ....../   
│   ├── document/                 # 文檔結(jié)構(gòu)
│   ├── app.json                  # 路由及頁面配置
│   └── typings.d.ts
├── build.json                    # 工程配置
├── f.yml                         # 函數(shù)平臺配置
├── midway.config.ts.             # midway 配置,主要指定接口和渲染目錄
├── package.json
└── tsconfig.json

從目錄來看,承載頁面渲染的核心業(yè)務(wù)邏輯如 pages、components 都無須改動(dòng)。SSR 模式下,服務(wù)端返回的不再是空文檔,而是經(jīng)過一次渲染后的文檔框架,所以需要保持代碼在 Node 環(huán)境下可運(yùn)行。由于汽車商詳在 Rax 多頁應(yīng)用開發(fā)時(shí)沒有這種環(huán)境約束,因此對技改提出了環(huán)境模擬的需求,這點(diǎn)在后面會(huì)著重提到。

數(shù)據(jù)請求

CSR 模式下,進(jìn)入頁面后拉取主接口數(shù)據(jù),執(zhí)行 js 完成頁面渲染。SSR 下,主接口數(shù)據(jù)需要在服務(wù)端獲得,完成服務(wù)側(cè)的文檔渲染。

97e4ddee-a38d-11ed-bfe3-dac502259ad0.png

客戶端得到的只是一個(gè)干文檔,需要再次執(zhí)行一遍 js 以激活文檔的事件監(jiān)聽、狀態(tài)傳遞等,成為可交互的頁面,這個(gè)過程也有一個(gè)形象的名稱,叫注水(hydrate):

97f664e2-a38d-11ed-bfe3-dac502259ad0.png

?請求流程的轉(zhuǎn)變

由于請求時(shí)機(jī)的改變,請求及其前后邏輯需要移至服務(wù)端執(zhí)行。

汽車商詳基于自建的一套端到端的渲染方案(XRoot)進(jìn)行接口設(shè)計(jì)和頁面渲染。接口數(shù)據(jù)中是組件集,包括各組件名稱和對應(yīng)組件需要的 props。我們封裝了一套 XRoot 組件,自動(dòng)執(zhí)行接口請求、數(shù)據(jù)注入、頁面渲染等工作。

在商詳首頁中,該接口請求的工作并不只是數(shù)據(jù)拉取與注入,還承擔(dān)了一系列請求前后的業(yè)務(wù)邏輯(如設(shè)置全局變量、容災(zāi)處理等)。對其中邏輯進(jìn)行抽象歸納,將業(yè)務(wù)邏輯聚合到 beforeRequest 和 afterResponse 中:

98175968-a38d-11ed-bfe3-dac502259ad0.png

SSR 模式下,主接口請求在服務(wù)端執(zhí)行,其執(zhí)行邏輯為:

9826d488-a38d-11ed-bfe3-dac502259ad0.png

afterResponse 邏輯中有一部分是對數(shù)據(jù)本身的處理,留在服務(wù)端實(shí)現(xiàn)。另一部分是 UI 相關(guān)的,需要在客戶端 Hydrate 階段再次執(zhí)行。

?中間層網(wǎng)關(guān)的模擬實(shí)現(xiàn)

在阿里集團(tuán)內(nèi),移動(dòng)端接口和后端的交互會(huì)經(jīng)過了一層 MTOP 網(wǎng)關(guān)。MTOP 網(wǎng)關(guān)提供了協(xié)議解析、安全防護(hù)、穩(wěn)定性保障等能力。SSR 模式下,服務(wù)端的數(shù)據(jù)請求無法經(jīng)過這層網(wǎng)關(guān),而是直接訪問后端 API。

此時(shí)業(yè)務(wù)依賴到的相關(guān) MTOP 能力需要業(yè)務(wù)側(cè)在 SSR 下手動(dòng)補(bǔ)齊,其中直接影響頁面渲染的就是 MTOP 對接口中空數(shù)據(jù)的處理:

9843a5fe-a38d-11ed-bfe3-dac502259ad0.png

原始接口數(shù)據(jù)中值為 null 的屬性都被 MTOP 層處理過了,如果 SSR 不做空值屬性的刪除,前端的默認(rèn)取值就會(huì)出問題:

const { text, tip = '默認(rèn)提示' } = tagsList[0];
console.log(tip); // 非空處理前:null ;非空處理后:'默認(rèn)提示'

這里寫一個(gè)簡單的工具函數(shù)來做這件事:

export const deleteNullProperties = (obj: Object | Array) => {
  const memory = new Set();
  const fn = (obj) => {
    if (memory.has(obj)) return obj;
    if (['[object Object]', '[object Array]'].includes(Object.prototype.toString.call(obj))) {
      for (const [key, value] of Object.entries(obj)) {
        if (value === null) {
          delete obj[key];
        } else {
          obj[key] = fn(value);
        }
      }
    }
    memory.add(obj);
    return obj;
  }
  return fn(obj);
}

?

另外,MTOP 網(wǎng)關(guān)還提供了用戶登陸態(tài)的解析與傳遞,SSR 側(cè)也需要業(yè)務(wù)自行從 cookie 中讀取用戶登陸信息

環(huán)境模擬

一般來說,由于服務(wù)端和瀏覽器端環(huán)境的差異,在做前后端同構(gòu)應(yīng)用的時(shí)候,開發(fā)者都會(huì)自覺注意環(huán)境差異,避免在不恰當(dāng)?shù)臅r(shí)機(jī)訪問瀏覽器對象,導(dǎo)致 SSR 側(cè)報(bào)錯(cuò)。

但是由于本次是改造項(xiàng)目,歷史項(xiàng)目只關(guān)注 CSR 場景,不可避免地充斥著預(yù)期以外的 DOM/BOM 訪問,此時(shí)有以下幾種解決方案:

987be2ca-a38d-11ed-bfe3-dac502259ad0.png

從改造成本和維護(hù)成本來看,借助框架能力和引入社區(qū)方案是兩種可以低成本探索的思路。

?框架能力

Rax 全棧應(yīng)用框架本身提供了在服務(wù)器端模擬瀏覽器環(huán)境的能力,從而來盡可能保證 SSR 和 CSR 編碼的一致性。其環(huán)境變量模擬的基本原則是:

  1. 所模擬的信息可由服務(wù)端數(shù)據(jù)推導(dǎo)得出,例如 location、navigator。

  2. 所模擬的信息不會(huì)引起代碼執(zhí)行邏輯的錯(cuò)誤,例如對 localStorage 的模擬。

從中可以看出,框架模擬能力并不旨在進(jìn)行環(huán)境模擬,相反它還在試圖為頁面提供一些真實(shí)有用的信息。因此框架提供的模擬能力相對有限,一些常用方法也沒有空方法占位,如試圖調(diào)用 window.addEventListener 時(shí)會(huì)報(bào) undefined 錯(cuò)誤。

由于 Hydrate 階段的存在,我們的目的只是希望代碼能夠在服務(wù)端不報(bào)錯(cuò),客戶端側(cè)的二次渲染會(huì)提供更加準(zhǔn)確的信息,框架能力并不能滿足需要。

?jsdom-來自社區(qū)的服務(wù)端環(huán)境庫

jsdom 是許多 Web 標(biāo)準(zhǔn)的純 JavaScript 實(shí)現(xiàn),特別是 WHATWG DOM和HTML標(biāo)準(zhǔn)。該項(xiàng)目并不是為了模擬服務(wù)端環(huán)境而存在,它的主要目標(biāo)是模擬足夠多的 Web 瀏覽器子集,使得頁面可以在服務(wù)端運(yùn)行,從而測試和抓取真實(shí)世界的 Web 應(yīng)用程序。 98b26980-a38d-11ed-bfe3-dac502259ad0.png ?它對瀏覽器環(huán)境強(qiáng)大的模擬能力可以幫助我們避免對項(xiàng)目源碼的改造。 由于 jsdom 同樣追求對功能性的模擬,功能強(qiáng)大的同時(shí),在服務(wù)端運(yùn)行時(shí)可能出現(xiàn)預(yù)料之外的問題,需要詳盡測試。在使用 jsdom 時(shí),也遇到了一些版本兼容問題,可以通過降低庫版本和動(dòng)態(tài)加載等方式解決。

其他問題

?降級策略

Rax 全棧應(yīng)用框架采取中間件降級策略,SSR 側(cè)有任何報(bào)錯(cuò)都會(huì)自動(dòng)將空文檔返回給客戶端,由客戶端發(fā)起數(shù)據(jù)請求和渲染,即降級為 CSR。

98e7fad2-a38d-11ed-bfe3-dac502259ad0.png

降級邏輯

99093382-a38d-11ed-bfe3-dac502259ad0.png

降級中間件源碼

業(yè)務(wù)側(cè)也可以根據(jù)需要使用框架提供的 useCSRRenderer 鉤子函數(shù)進(jìn)行主動(dòng)降級:992b1196-a38d-11ed-bfe3-dac502259ad0.png

?自閉合標(biāo)簽問題

習(xí)慣了 react 的 JSX 語法體系,我們通常會(huì)寫出許多自閉合標(biāo)簽以提高可讀性和代碼整潔性:

// 自定義組件的自閉合



// 原生標(biāo)簽的自閉合

但事實(shí)上 HTML 規(guī)范并不支持對

的解析,以一個(gè)簡單的 demo 為例:

995a3a66-a38d-11ed-bfe3-dac502259ad0.png

在開發(fā)者的期待里,b 和 c 同級,d 是 c 的子標(biāo)簽。但實(shí)際渲染結(jié)果中,c 成了 b 的子級。 對這種情況的一種表象理解是,瀏覽器把自閉合標(biāo)簽當(dāng)作正常
頭處理,為其匹配了一個(gè)
。到最后閉合標(biāo)簽不夠用了,瀏覽器自動(dòng)加了兩個(gè)
,導(dǎo)致文檔結(jié)構(gòu)發(fā)生了變化:

997305be-a38d-11ed-bfe3-dac502259ad0.png

為什么在 JSX 中寫自閉合標(biāo)簽?zāi)軌虻玫狡诖械慕Y(jié)果呢?事實(shí)上是 CSR 框架側(cè)幫我們做了這件事,如 react 在其官方文檔里就有提到:react地址:https://react-cn.github.io/react/tips/self-closing-tag.html 9982eb46-a38d-11ed-bfe3-dac502259ad0.png

從實(shí)踐來看,Rax 框架在 CSR 側(cè)的渲染同樣做了類似的處理,但是 Rax 全棧應(yīng)用的服務(wù)端渲染沒有,其 SSR 側(cè)生成的文檔只是簡單將自閉合標(biāo)簽原樣返回:

9993b462-a38d-11ed-bfe3-dac502259ad0.png

不同階段下的文檔結(jié)構(gòu)

由于在 hydrate 階段瀏覽器判斷 ssr 文檔與客戶端預(yù)期不一致時(shí),會(huì)被丟棄掉重新渲染,所以這種處理沒什么功能性問題。只是這樣就失去了 SSR 的首屏優(yōu)化功能。在 Rax 團(tuán)隊(duì)完善自閉合標(biāo)簽問題之前,業(yè)務(wù)側(cè)需要避免寫出非自定義標(biāo)簽的自閉合。

?與 CSR 倉庫的功能同步

因?yàn)槲覀兪菍?CSR 項(xiàng)目的改造,為了不影響線上功能,另啟了一個(gè)應(yīng)用倉庫。隨著改造的進(jìn)行,原 CSR 項(xiàng)目也一直在接新需求不停迭代。 借助 git merge --allow-unrelated-histories 機(jī)制,我們在代碼同步方面不必投入太多成本。但是為一個(gè)業(yè)務(wù)場景維護(hù)兩套應(yīng)用,其中需要付出的溝通、維護(hù)、測試等成本還是很高。

?下一步計(jì)劃

如前所述,兩個(gè)應(yīng)用的維護(hù)成本較高。因?yàn)閮烧叩目蚣芑A(chǔ)是一致的,我們就希望將兩個(gè)應(yīng)用合并起來,至少能降低一點(diǎn)代碼同步和溝通成本。與技術(shù)支持同學(xué)溝通了一下,發(fā)現(xiàn)沒有這個(gè)先例,可能會(huì)有很多意料之外的問題,所以這部分仍在試錯(cuò)中。

小結(jié)

借著本次服務(wù)端渲染(SSR)改造升級的實(shí)踐,我對前端的渲染機(jī)制也有了更深入的理解。雖然 SSR 相較于 CSR 有著許多優(yōu)勢,卻未成為 Web 渲染的主流模式,是因?yàn)闃?gòu)建 SSR 應(yīng)用并不輕松:需要熟悉服務(wù)端開發(fā)、了解服務(wù)端和客戶端的環(huán)境差異、服務(wù)部署、服務(wù)器運(yùn)維等,對前端開發(fā)提出了更高的要求。

而云原生基礎(chǔ)設(shè)施的蓬勃發(fā)展、Nodejs FaaS 函數(shù)服務(wù)建設(shè)的逐漸完善,都將大大降低 SSR 應(yīng)用的接入門檻。前端開發(fā)者將只需關(guān)注業(yè)務(wù)邏輯就能輕松獲得 SSR 能力,用戶也更有機(jī)會(huì)得到更好的交互體驗(yàn)。

審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6772

    瀏覽量

    88651
  • 函數(shù)
    +關(guān)注

    關(guān)注

    3

    文章

    4263

    瀏覽量

    62250
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4700

    瀏覽量

    68117

原文標(biāo)題:天貓汽車商詳頁的SSR改造實(shí)踐

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    馬云發(fā)話:雙十一,淘寶要突破一千億(13億人的舔屏?xí)r代)

    摘要 :去年雙十一天的成交額是571億,而今年馬云更是花盡各種心思,馬云發(fā)話:今年雙十一,淘寶突破一千億!?。∪ツ甑碾p十一,是平
    發(fā)表于 11-11 19:29

    618粉絲狂歡節(jié)-haier和聯(lián)專賣店

    `  粉絲狂歡節(jié)是一年一度的618年中大促活動(dòng)。作為商家:haier和聯(lián)專賣店,我們不說話、只比價(jià)、更有精美大禮相送。海量商品,一站購齊。品牌直營,正品保障,安全便捷!`
    發(fā)表于 06-16 14:33

    、泰捷盒子哪個(gè)更好用?深度解析四大差異點(diǎn)

    ``、泰捷盒子哪個(gè)更好用?深度解析四大差異點(diǎn) 說到電視盒子,、泰捷盒子是目前最暢銷的兩大品牌,但是很多新手用戶并不清楚,它們的核心功能以及定位等,究竟有什么區(qū)別,一不小心買到不
    發(fā)表于 08-25 16:07

    枯木:雙11項(xiàng)目組織協(xié)同

    摘要: 2018第二屆研發(fā)效能嘉年華峰會(huì),云效邀請技術(shù)部高級技術(shù)專家吳建和(枯木)帶來題為雙11項(xiàng)目組織協(xié)同的演講。主要內(nèi)容是從四個(gè)方面進(jìn)行講解的,首先詳細(xì)介紹了項(xiàng)目的特性,然
    發(fā)表于 06-07 18:00

    ar識別什么意思

    `  誰來闡述一下ar識別是什么意思?`
    發(fā)表于 08-28 17:49

    Lua游戲開發(fā)實(shí)踐指南 -

    Lua游戲開發(fā)實(shí)踐指南 - 章.pdf
    發(fā)表于 01-14 16:13 ?29次下載

    vivo與成立“新機(jī)研究所”,借助數(shù)據(jù)造手機(jī)

    vivo宣布借助大數(shù)據(jù)造新手機(jī),聯(lián)合成立“新機(jī)研究所”。不僅借助大數(shù)據(jù),消費(fèi)者還能
    發(fā)表于 08-02 17:16 ?691次閱讀

    夏天,改造上網(wǎng),MODEM改造

    夏天,改造上網(wǎng),MODEM改造 關(guān)鍵字:散熱改造 作者:非誠勿擾—唐少 這幾天,。。。。。天氣。。。。真的。。。好熱。。
    的頭像 發(fā)表于 09-20 18:54 ?572次閱讀

    魔盒3評測 輕薄同樣有實(shí)力

    又到了一年一度的雙十一,眾多廠商都在為這個(gè)購物狂歡節(jié)不斷增加自身競爭力。魔盒當(dāng)然也不例外,本次雙十一,魔盒推出了多款新品,包括
    的頭像 發(fā)表于 11-15 09:19 ?7151次閱讀

    阿里戰(zhàn)略組織架構(gòu)再調(diào)整 將變得更大

    11月26號,阿里公布了一年一次的組織架構(gòu)調(diào)整。阿里CEO張勇發(fā)布公開信,宣布阿里最新一次組織升級:阿里云升級為阿里云智能;升級為大,形成天
    的頭像 發(fā)表于 11-26 17:31 ?3414次閱讀

    京東店關(guān)閉 HTC否認(rèn)放棄手機(jī)業(yè)務(wù)

    近日,有網(wǎng)友發(fā)現(xiàn),HTC手機(jī)旗艦店和京東旗艦店已經(jīng)關(guān)閉。其中,平臺上的官方旗艦店已無法打開,京東平臺上則無法搜索到。
    的頭像 發(fā)表于 05-12 09:33 ?2831次閱讀

    “618”開賣46秒服飾破億

    6月1日,“618”第一小時(shí)就迎來開門紅。0點(diǎn)剛過僅僅46秒,服飾就破億,開賣7分鐘,銷售破10億,同比增幅高達(dá)40%。
    的頭像 發(fā)表于 06-04 14:28 ?2883次閱讀

    V榜TOP100:海爾56度C、美的、格力均上榜

    3月2日,#V榜出書了#登上微博熱搜TOP3,受到網(wǎng)友極大關(guān)注。從話題上看到,這是首本官方購物指南《
    的頭像 發(fā)表于 03-04 12:43 ?2767次閱讀

    否認(rèn)“大數(shù)據(jù)殺熟” 部分用戶不買賬聯(lián)系消協(xié)

    但在剛剛過去的超市的“38節(jié)”活動(dòng)中,有網(wǎng)友發(fā)現(xiàn),超市同一款商品對不同用戶的售價(jià)不一
    的頭像 發(fā)表于 03-12 16:17 ?2198次閱讀

    魔盒實(shí)際性價(jià)比怎么樣,現(xiàn)在值不值得買

    魔盒是這個(gè)平臺主推的電視盒子產(chǎn)品,很多人最開始買電視盒子的時(shí)候都會(huì)考慮到魔盒,那么
    的頭像 發(fā)表于 02-17 17:20 ?1.2w次閱讀
    <b class='flag-5'>天</b><b class='flag-5'>貓</b>魔盒實(shí)際性價(jià)比怎么樣,現(xiàn)在值不值得買