作者:京東科技 陳云飛
一,需求背景
1 業務背景
在以往的業務場景中,用戶進入五花八門的選單體系中,往往會產生迷茫情緒,難以理解平臺名稱及具體作用,導致資料開發與管理學習成本較高,降低作業效率,為此我們整合從資料接入,資料開發,資料管理的全鏈路流程,期望讓用戶體驗一站式資料開發與管理的便捷性;并提供不同業務場景,方便根據業務場景進行進一步資料開發與管理作業,為資料應用平臺打下夯實規范的資料基礎,方便用戶在資料平臺里,對于資料開發和資料應用進行便捷性的切換,因此我們設計目前的門戶基座,可以快速瀏覽各個平臺,同時串聯資料開發與管理的作業,減少用戶的試錯成本,提升作業效率,
2 標品需求
基座子-專案互動簡圖如圖1;
1,基座的業務頁面比較簡單,主要包含:頂部邊欄、左側邊欄、公共子選單、頂級平臺選單;
2,點擊左上角圖示,顯示頂級平臺選單,點擊平臺,在基座左側邊欄動態顯示平臺一級選單;
3,點擊基座左側邊欄,在公共子選單,動態顯示一級選單下邊的二級、三級選單;
4,點擊基座左側邊欄或者公共子選單,需要基座調度,在子專案區域正確加載子專案及子專案頁面;

圖 1
資料中臺新門戶基座要接入老資料平臺一、老資料平臺二等 多平臺的前端專案,并且原有前端子專案在門戶基座呈現任意子專案、任意子專案頁面 任意混搭的需求;新門戶要接入的專案關系詳情如圖2;

圖 2
3 資料中臺融合;
資料中臺融合指的是京東體系內,其他對外獨立交付的資料中臺,比如京東工業、京東城市等專案;資料中臺商業化的子專案不僅在新門戶容器內,也可以按需打包進其他資料中臺容器;下面簡稱 資料中臺融合;
二,微前端技術調研
原有資料中臺接入子應用的方式有多種:iframe 嵌套、@weus 微應用、鏈接跳轉等;
1 iframe 存在問題:
? url 不同步,瀏覽器重繪 iframe url 狀態丟失、后退前進按鈕無法使用,
? UI 不同步,DOM 結構不共享,想象一下螢屏右下角 1/4 的 iframe 里來一個帶遮罩層的彈框,同時我們要求這個彈框要瀏覽器居中顯示,還要瀏覽器 resize 時自動居中..
? 全域背景關系完全隔離,記憶體變數不共享,iframe 內外系統的通信、資料同步等需求,主應用的 cookie 要透傳到根域名都不同的子應用中實作免登效果,
? 慢,每次子應用進入都是一次瀏覽器背景關系重建、資源重新加載的程序,
2 weus 存在問題:
?weus 是京東內部研發已經不再維護了,如果有新的問題需要自己解決,對微前端有新需求也需要自己去實作;
?weus 沒有嚴格的 css 沙箱、js 沙箱,而在我們的需求中,沙箱機制是剛需,我們要接入的子專案在 window 上掛在哪些變數,無法通過規范做到強有力的制約(因為要接入的專案是已經寫完了)
?weus 在微前端功能實作,沒有qiankun 豐富健全,比如全域狀態管理、雖然 weus 實作了子應用的預加載,但是比較機械,是把所有注冊的子應用都快取,實際可能不需要,qiankun 就比較靈活可以根據需要手動快取等;
3 鏈接跳轉
鏈接跳轉,指的是點擊一個選單,跳轉到另一個頁面,這種方式不符合 “一站式 ”大資料平臺產品定位;
4 最終結論
通過幾種實作方式的對比,最終決定以 qiankun 微前端為基礎,結合我們的實際業務場景,通過權限選單樹 和 子專案關聯來實作基座對子專案的調度,具體方案請參照 三,基座技術方案詳細描述;
三,技術方案詳細描述;
1 名詞解釋
跨子專案跳轉
指的是子專案沒通過基座自行跳轉,基座此時需要根據 url 匹配正確的基座顯示;
觸發節點
點擊選單,選單對應的節點即為觸發節點,跨子專案跳轉(重繪頁面)沒有觸發節點,以跳轉后url 對應的頁面節點為觸發節點;
頁面節點
權限選單樹中,掛載了子專案頁面的節點
門戶節點
狹義指的是,當前頁面節點對應的公共子選單父級節點;廣義指的是通過頁面節點向父系節點查詢,最終確認公共子選單、基座邊欄的顯示,并通過頁面節點確定選單高亮等行為;
第一子系節點
指的是在由觸發節點查頁面節點時,只關注子節點中的第一個,如果當前節點的第一個節點不是頁面節點,繼續在孫子節點的第一個,直到節點型別為頁面節點為止;
調度引擎
指的是在基座中,對權限樹資料處理,接識訓座業務層調度,通過對權限樹遍歷、查詢操作對業務層輸出運算結果的一個抽象分層;
2 整體流程圖
如圖3 為基座技術方案的整體流程圖,下面詳細介紹

圖 3
3 技術方案-分步描述
第 1 步,配置權限選單樹,關聯子專案頁面
?如圖 3 所示,首先會在權限中心配置權限選單樹,權限選單樹有很多級,比如一級平臺,二級平臺,二級平臺一級選單,二級選單等,三級選單等;
?然后需要在選單樹上,掛在子專案的頁面,子專案頁面的一些權限按鈕等;
?最后權限中心對不同的用戶賦予權限選單樹的子集;
第 2 步,基座選單樹資料處理;
?基座從介面拿到權限選單樹關聯頁面資料后,觸發調度引擎初始化、并把基座的業務更新函式傳給調度引擎;
?基座獲取到選單樹以后,廣度優先演算法(如圖4)遍歷整個樹結構,并建立節點間父子關聯關系,根據節點是否掛載了子專案頁面定義前端節點型別 ;最終形成圖 5 的資料;
?在樹遍歷程序中,會統一在基座左側邊欄這一層級的節點,做一個門戶節點的標記;

圖4
?如圖 5 所示,前端調度關系中,把權限選單樹分成 兩種節點型別,掛載了子專案頁面的節點,定義為頁面節點,另一種沒掛載子專案頁面的節點,定義為分組節點;在基座調度中,不關心權限按鈕節點,在資料處理中,頁面節點就是整個權限選單樹的葉子節點;

圖 5
第 3 步,點擊基座邊欄或公共子選單
?點擊基座邊欄,觸發點擊選單流程,點擊的節點即為 “觸發節點”;
?由觸發節點,向第一子系節點查頁面節點,查頁面節點同時,會同時匹配門戶節點;
?沒有匹配到門戶節點,由觸發節點向父系節點匹配門戶節點;
第 4 步,重繪頁面或跨子專案跳轉
?這時沒有直接的觸發節點,只能通過 url 上的標識和選單樹上的頁面節點進行匹配
?匹配到頁面節點以后,由頁面節點向父系節點查門戶節點;
第 5 步,通過門戶節點輸出 “運算結果”
?這里的運算結果主要包含:基座左側邊欄、公共子選單選單樹串列、選單高亮、產品平臺名稱等一系列基座需要正確顯示所需要的資料;
?基座調度引擎,根據觸發調度的型別;如果是點擊選單觸發會執行 切換頁面操作,重繪和跨子專案跳轉則不需要觸發;
第 6 步,基座業務層執行運算結果;
?基座調度引擎,在接識訓座業務層調度指令后,通過對圖 5 權限樹的遍歷、查詢操作,最侄訓取運算結果;
? 呼叫基座業務層的更新函式,執行運算結果,到此基座調度流程結束;
四,基座-子專案結構通信圖
1 基座分為業務層、調度引擎兩部分;
?基座業務層主要包含:左側邊欄、頂部邊欄、頂級平臺選單等 UI顯示;
?基座調度層,以 qiankun 微前端為基礎,豐富擴展了權限樹資料處理、調度運算、雙向通信、子專案分組分步預加載策略等;
2 基座子專案通信和路由調度
?基座在執行主題切換時候,通過 qiankun 的 setGlobalState 通知子專案;子專案在系結專案空間等特定需求時,通過調度引擎封裝的 eventCenter 和基座反向通信;
?跨子專案跳轉,子專案會自行觸發 pushState,點擊基座選單跳轉流程,由調度引擎觸發 pushState 觸達
? qiankun 的 pushSate 劫持策略,觸發 popstate 子專案頁面因此觸發更新;

圖 6
3 路由劫持策略原理
基座調度引擎通過監聽 popstate 來獲取重繪、跨子專案跳轉的指令,從而觸發調度流程;以下為原理決議:
?以 Vue 為例,Vue 通過 主動觸發 pushState、replaceState 或者監聽 popstate 變化觸發頁面發生變化;
?但是跨子專案跳轉,執行 pushState 并沒有觸發 popState 基座調度引擎又怎么能監聽到呢?
?通過閱讀 qiankun 中依賴的庫 single-spa 的原始碼,navigation 模塊劫持了 pushstate 方法,只要觸發 pushstate,就會觸發 popstate 事件,關鍵代碼如下所示:
function patchedUpdateState(updateState, methodName) {
return function () {
const urlBefore = window.location.href;
const result = updateState.apply(this, arguments);
const urlAfter = window.location.href;
if (!urlRerouteOnly || urlBefore !== urlAfter) {
if (isStarted()) {
window.dispatchEvent(
createPopStateEvent(window.history.state, methodName)
);
} else {
reroute([]);
}
}
return result;
};
}
window.history.pushState = patchedUpdateState(
window.history.pushState,
"pushState"
);
五,基于 qiankun 功能擴展:
1 沙箱隔離
js 沙箱利用 qiankun 沙箱機制;
css 沙箱,qiankun 的 css 沙箱不健全;我們接入的又是老專案,目前的策略是 :
?基座通過特殊命名空間 .susceptor、element-ui 通過 .spr 跟子專案隔離;
?子專案通過特殊命名空間,例如 .datacenter-xxx 跟基座隔離
?子專案對 .el- 不執行隔離,目的是為了統一控制布局、主題,同時做性能優化;
2 通信機制
基座和子專案,屬于典型的主從結構,采用單向資料流通信;為了滿足特殊場景子專案跟基座通信需求,在 qiankun 的通信基礎上,封裝了 eventCenter 僅用于 子專案 跟基座通信;
?基座 -> 子專案,通過qiankun 的 onGlobalStateChange 通信
?子專案 -> 基座,通過 subActions 封裝的 eventCenter 通信
3 分組、分步、動態預加載機制
目前標品基座已經加載了 30多個前端子專案,這么多前端子專案在首個子專案掛載后執行預加載,有可能會阻塞正常頁面訪問;
分組指的是,通過產品劃定的平臺,只有切換到當前平臺才會加載到當前平臺的子專案;
分步指的是,當前平臺子專案過多時,一次預加載少量子專案,分多次預加載;
動態指的是,基座在首個子專案掛載后,會檢測網速,只有網速良好時才會執行預加載;
4 跨子專案跳轉
跨子專案跳轉的背景在于 BDP 一站式開發與管理平臺,是一個大產品,資料規劃、資料集成 等是其中的模塊;模塊之間存在一些跳轉,對于前端就是跨子專案跳轉;
我們目前的跨子專案跳轉,由 subActions 封裝,抹平了標品基座 和 資料中臺融合容器的區別;
基座跳轉邏輯如下:
crossAppJump: ({ subApp='', path= '', paramsStr='', target= ''})=> {
let jumpUrl = `/susceptor/${subApp}${path}`
if(paramsStr){
jumpUrl = `${jumpUrl}${paramsStr}`
}
if(target === '_blank'){
window.open(`${location.origin}${jumpUrl}`)
} else {
window.history.pushState({ portalPushState: true }, null, jumpUrl);
}
},
資料中臺融合跳轉邏輯如下:
crossAppJump: ({ subApp='', path= '', paramsStr='', target= ''})=> {
let jumpUrl = `/${subApp}${path}`
window.__datafuse_jssdk__.crossAppJumpFnGetter({
path: jumpUrl,
paramsStr,
target
})();
}
5,介面訪問及登錄鑒權;
由于微前端的技術形態,子專案在基座中加載實質是基座容器的 一段 html,所有介面均是以基座的 域名進行介面轉發;由因為資料中臺融合,所以子專案請求后端介面均是以 /api/datacenter/專案名 開頭;
通過以下 nginx 示例,我們把基座、子專案 的頁面訪問、介面訪問鏈路 說明白;
# proxy.conf 示例(已做脫敏處理,均不是專案升級名稱)
server {
listen 80;
server_name unify.external.dadacenter;
charset utf-8;
location /sub-app{
alias /export/web/sub-app-web;
try_files $uri $uri/ /index.html =404;
}
location /api/datacenter/subapp {
proxy_pass http://server-sup-app/;
}
location /susceptor{
alias /export/web/susceptor; on;
try_files $uri $uri/ /index.html =404;
}
location /api{
proxy_pass http://sever-api/;
}
}
# server.conf 示例(已做脫敏處理,均不是實際專案)
upstream server-sup-app{
server 111.112.113.114:10001;
}
upstream sever-api{
server 111.112.113.114:1000;
}
鑒權,前端不需要開發,但是需要知道,后端是通過頂級域名種 cookie 鑒權的;例如:unify.external.bigdata 測驗環境是在 .external.bigdatao 域名下,這也是為什么本地開發需要配置 host:127.0.01 loca.external.dadacenter ;
六,寫在最后,不忘初心
本節提供兩個圖, 對上文介紹的微前端實踐,有進一步的能力提升,有感興趣的同學歡迎一起討論;
1,整體流程圖;
如圖 6 所示,配置流程:配置權限選單樹,然后配置子專案-子專案頁面兩級;最后把權限選單樹 和 子專案-子專案頁面關聯起來,形成如圖 7 的權限樹-子專案關聯資料模型;
基座兩個調度流程,跟上文類似,但是多了子專案維度,基座在加載子專案的時候,就可以把子專案 在權限樹的 權限按鈕資訊全部給到子專案;

圖 6
2 權限選單樹模型;
上文介紹的基座調度流程是簡化后的版本,專案節點只有 分組節點、頁面節點;但是從能力層缺失了 子專案維度;在設計之初,如圖 7 所示:專案節點包含了 分組節點、子專案節點、子專案頁面節點、頁面節點 4種節點型別;

圖 7
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/550806.html
標籤:Html/Css
上一篇:學系統集成專案管理工程師(中項)系列07_資訊(檔案)管理
下一篇:返回列表
