易盾移動端同構實踐,幾步改善官網互動體驗

網易易盾發表於2021-08-05

背景


為了首屏渲染更快,讓使用者更快看到內容,網易易盾開啟了移動端官網同構建設,即一套程式碼兩端執行, 客戶端程式碼直接執行在服務端, 無需編寫冗餘的渲染檢視。


改造前,官網專案的技術棧較大眾,以 egg.js 為後端框架,Nunjuck 為模板,前端採用 jQuery。


本次則採用Vue 作為前端框架進行了部分改進,團隊成員的技術儲備也基本上建立在 Vue 的技術體系上,從以下3方面出發,重整技術選型,全面改善易盾的官網生態。


統一技術棧:Nunjuck 模板很強大,但和我們習慣用的 Vue 語法還是有些不同。而 jQuery 屬於舊時代的產物,資料驅動檢視的思想已經深入人心。


使用者體驗:同構後的前端能兼顧 SEO 和 SPA 的互動體驗。


開發體驗:更易和現代的開發構建工具整合,如 webpack、ESLint、SASS 等。



技術選型


方案一:Vue SSR 官方指南 https://ssr.vuejs.org/zh/

專案地址:https://github.com/vuejs/vue-hackernews-2.0/


優缺點分析:

1.自由度最高,不依賴 node 框架和 vue 相關任何生態

2.需要的工作量最大,主要是 vue-ssr 通用邏輯 & 前端構建配置的實現

3.可複用目前基於 eggjs 的後端邏輯


方案二:nuxt.js


優缺點分析:

1.完善的解決方案,提供了許多開箱即用的功能,能大大減少很多配置和通用邏輯實現

2.不依賴 node 框架,主要關注的是應用的 UI 渲染

3.需要完成 egg.js 後端 api 介面的邏輯遷移


方案三:egg.js 和 nuxt.js 結合

以 egg.js 為主,nuxt.js 降級為 egg.js 一箇中介軟體。這種方案可行得益於 nuxt.js 不依賴 node web 框架。


1.複用目前 node 端邏輯,僅對檢視做遷移

2.利用 nuxt.js 提供的開箱即用的特性,無需關注 vue-ssr 通用邏輯實現和前端複雜的構建配置

3.工作量之一需要完成 eggjs 和 nuxt.js 的結合,提供一個 eggjs 中介軟體


方案三既能利用了 nuxt.js 的能力,且無需對目前 node 端邏輯做改動,很好的滿足了我們的需求。基於該方案的流程圖如下:

圖片



落地過程


【egg-nuxt-render 外掛的實現】


外掛中介軟體的實現關注點:

圖片


  1. 請求未命中 egg 路由時會返回 404,中介軟體處理 404 請求,修改 status 為 200,後續交於 nuxt.js 處理。如果 nuxt 路由中也未命中,由 nuxt 提供 404 頁面。

  2. 傳遞 egg ctx,使得 nuxt 中能獲取到 egg 的上下文。

  3. 呼叫 nuxt.render,即完成將當次請求交於 nuxt.js 處理。



【專案目錄】


至此,我們可以這樣設計我們的目錄結構。僅需在 eggjs 根目錄下新增 client 目錄,來放置 nuxt.js 的所需的各種目錄(每個目錄的含義可參考 nuxt 官方文件)。nuxt.config.js 為 nuxt 的配置檔案,會被 egg-nuxt-render 外掛讀取。


圖片



【頁面遷移】


到了這一步,我們就可以開始遷移我們的頁面了,即 Nunjuck 模板重構為 vue 模板。刪除原先 egg router 中的頁面路由定義,然後在 client/pages 裡新增對應的頁面.vue。這一步是體力活,也是本次同構最費時間的工作。看到這裡有人可能會疑惑,這種方案需要要求所有的頁面一次性重構完成,如果專案很龐大,沒辦法一次性重構完或者或者一次性重構完風險極高的情況下,是不是就很難實施了?考慮到這種合理的情況,設計了另一個相容方案,給大家提供一種思路。



【相容方案】


因為我們團隊的專案規模可控,故採用一次性重構完所有頁面。


方案流程圖如下:

圖片

注意:本方案未經線上測試,僅供參考


這種方案的核心想法是先渲染 Nunjuck 模板,然後透過 ctx 將渲染結果傳遞到 nuxt 的 vue 模板完成最終渲染。主要可以關注以下幾點:


1.保留 eggjs 頁面路由的定義,呼叫 htmlRender 將 Nunjuck 模板轉化成 html 字串,並且儲存到ctx.__HTML_RENDER__。此時需要將 status 置為 404。 


圖片


2.由於 status 為 404,會執行 egg-nuxt-render 中介軟體,進入 nuxt 路由。但此時 nuxt 中並沒有該路由(因為該頁面未重構),所以我們將其指到同一個元件,即 NjkWraper.vue。


圖片


3.NjkWraper.vue 負責渲染 __HTML_RENDER__ 內容。__HTML_RENDER__ 應僅包含每個頁面的主體部分,不包含頁面通用部分(如導航、底部等),此部分由 vue 實現。


圖片



4.由於所有的路由都會命中 NjkWraper.vue,會導致真實的 404 請求丟失。所以我們還需要做一步判斷該請求是不是真實的 404 請求。如果是,則需要重定向到 404 頁面。這一步可在 vue router 守衛中實現。


圖片


至此,我們只要先將頁面通用部分,如導航、底部等,透過 vue 重構,具體頁面後面可以慢慢遷移。


相容方案存在的弊端:


頁面間跳轉必須重新整理頁面。因為最終輸出到瀏覽器的頁面中會包含 vue 元件 和 Nunjuck 渲染出來的內容,其中 Nunjuck 內容中可能存在 jquery、regular 等各種庫,重複引入恐有問題。


所有頁面重構完後,相容程式碼需要刪除。



總結


本次的同構實踐本質上是對已有專案的重構,考慮了系統穩定性和重構成本,故未對 egg.js 主框架做調整。當開啟一個新的專案時,直接採用 nuxt.js 提供的完整的解決方案會更加純粹。



相關文章