1. <big id="iqoas"></big>
      <tr id="iqoas"></tr>
      「睿思設計」深圳網站建設-網站設計制作公司-小程序開發

      Internet Develppment互聯網開發&設計服務提供商

      SEARCH

      與我們合作

      我們專注:網站策劃設計、網絡多媒體傳播、網站優化及網站營銷、品牌策略與設計
      主營業務:網站建設、移動端微信小程序開發、VI設計、網絡運營、云產品·運維解決方案

      有一個品牌項目想和我們談談嗎?

      您可以填寫右邊的表格,讓我們了解您的項目需求,這是一個良好的開始,我們將會盡快與您取得聯系。當然也歡迎您給我們寫信或是打電話,讓我們聽到您的聲音

      您也可通過下列途徑與我們取得聯系:

      地 址: 深圳市龍華區尚美中心12樓

      電 話: 15915432684

      微 信: 15989169178

      郵 箱: idea@runideas.com

      網 址: http://www.cstexnet.com

      快速提交您的需求 ↓

      看不清?請點擊我

      微前端框架核心技術揭秘

      發布日期:2022-07-03  瀏覽次數:144  關鍵詞:微前端 Micro Frontend


      2016年由ThoughtWorks提出了一種類似微服務的概念“微前端”(Micro Frontend),其后該概念在web領域逐漸落地,在前端技術領域出現了繁多的微前端框架。本文將向你介紹有關微前端的概念、意義,帶你走近微前端框架,揭秘那些“不為人知”的巧妙技術實現。

      概念

      什么是微前端呢?雖然它在2016年就被提出,但是直至今天,我們仍然只能描述它的輪廓,無法給它清晰下定義。以下是筆者閱讀到的一些有關對微前端概念的闡述:

      • 微前端是一種類似于微服務的架構,它將微服務的理念應用于瀏覽器端,即將單頁面前端應用用由單一的單體應用轉變為把多個小型前端應用聚合為一的應用。各個前端應用還可以獨立開發、獨立部署。同時,它們也可以進行并行開發?!肚岸思軜嫞簭娜腴T到微前端》
      • 微前端背后的想法是將網站或Web應用視為獨立團隊擁有的功能組合。 每個團隊都有一個獨特的業務或任務領域,做他們關注和專注的事情。團隊是跨職能的,從數據庫到用戶界面開發端到端的功能?!g,micro-frontends.org
      • 微前端的核心價值在于 "技術棧無關",這才是它誕生的理由,或者說這才是能說服我采用微前端方案的理由?!猭uitos, qiankun作者,2020.11.20晚阿里云微前端線下沙龍
      • 真正要解決的是,當技術更新換代時,應用可兼容不同代際的應用。

      微前端是一種架構,而非一個獨立的技術點。我個人從兩個角度去看微前端,一個是應用結構上,微前端是多個小應用聚合為一的應用形式;一個是團隊意識上,微前端架構下,每個團隊只負責獨立(封閉)的功能,而且需要包含從服務端到客戶端,團隊協作意識與以往有較大不同。

      微前端方案

      如何在技術上落地實現微前端的概念呢?在前端技術領域出現了如下三種技術方案:

      • 基于接口協議的:子應用按照協議導出幾個接口,主應用在運行過程中調用子應用導出的這幾個接口
      • 基于沙箱隔離的:主應用創建一個隔離環境,讓子應用基本不用考慮自己是在什么環境下運營,按照普通的開發思路進行開發即可
      • 基于模塊協議的:主應用把子應用當作一個模塊,和模塊的使用方式無異

      三種方案各有優劣,我們不能立即下結論哪一種更好。

      方案類型典型技術優點缺點共同點
      接口協議single-spa比較自由,可自主封裝無法滿足很多場景
      • 子應用/模塊互不干涉
      • 技術棧無關
      沙箱隔離qiankun開發思維簡單直接沙箱帶來的性能等問題
      模塊協議webpack module federation用模塊思維理解引用脫離構建工具無法使用

      就目前市面上的情況而言,基于沙箱隔離的微前端方案占據了主導,也就是本文將要深入闡述的微前端框架們,也都是這類方案。其中原因,筆者認為最主要的一點,是基于沙箱隔離的方案可以讓應用以最小的成本,從原本的單體大應用遷移到微前端架構上來。

      微前端框架對比評測

      微前端框架是用于快速讓web站點或其他技術棧切換到微前端架構的底層引擎,市面上有非常多的微前端框架,筆者在2021年做過一次收集,比較有典型意義。(雖然在那之后還出現了新的微前端框架,但其大部分原理一致,因此,以下這些框架足以說明情況。)

      • Mooa:基于Angular的微前端服務框架
      • Single-Spa:最早的微前端框架,兼容多種前端技術棧。
      • Qiankun:基于Single-Spa,阿里系開源微前端框架。
      • Icestark:阿里飛冰微前端框架,兼容多種前端技術棧
      • console-os 是在阿里云控制臺體系中孵化的微前端方案, 定位是面向企業級的微前端體系化解決方案。
      • Module Federation:webpack給出的微前端方案
      • Luigi:一套復雜的分布式前端應用解決方案
      • FrintJS:自主解決依賴的微前端框架
      • PuzzleJS:一套復雜的前后端編譯時相結合的微前端解決方案
      • ngx-planet:基于angular的微前端框架
      • 麥飯(mfy):精巧簡易的微前端框架

      除了webpack的聯邦模塊方案需要結合構建來做,比較特殊外,其他方案都是在運行時完成應用聚合。 “子應用獨立運行”指子應用不需要放到基座應用這個大環境下就能自己跑,便于調試和被不同基座引入。 “子應用嵌套子應用”是一個比較特殊的點,目前市面上能做到的框架不多。

      微前端框架核心技術

      在微前端架構中,存在“主應用”和“子應用”兩個層級,而微前端框架的主要任務就是讓子應用能夠在主應用中有效運行。如上文所述,目前較多的微前端框架是基于(或支持)沙箱隔離實現的主子應用運行機制,筆者自己實現的小型微前端框架“麥飯”也屬于此類,因此,本文只深入闡述這類微前端框架的技術原理及實現。微前端框架要解決的核心問題是資源加載和環境隔離兩大問題,此外,還有路由、通信等問題。

      資源加載

      微前端框架需要從服務端拉取子應用的代碼文件,并完成解析和子應用的掛載運行。拋開webpack的模塊聯邦方案,現在常見的有兩種方案,分別是:以JS文件作為入口;以HTML文件作為入口。以JS文件作為入口可以直接運行JS腳本,獲得JS導出的內容,但是這樣,僅能加載腳本資源,無法加載CSS等樣式資源。而以HTML文件為入口,則可以通過HTML文件內的文件引用,把對應的所有JS、CSS文件都一起加載,而且,web站點都是以HTML文件作為入口,這也正好可以讓子應用的開發者按照web開發的思路來寫子應用。 筆者在寫麥飯這個框架的時候,希望直接引入子應用就能跑,所以以HTML作為入口文件。開發者使用一個特殊的importSource函數來引入入口文件,這個函數可以根據入口文件,解析子應用的全部資源,并做緩存。

      解析資源

      框架在獲得HTML入口文件地址后,通過HTTP請求獲得該文件的內容,對內容進行解析,解析時需要做資源樹分析,也就是通過HTML讀取所有資源文件,比如link, script[src]。在讀取資源時,可能還需要讀取資源本身又引入的資源。大致邏輯如下圖:在解析過程中,還需要根據registerMicroApp(麥飯提供的注冊接口)的配置,決定CSS rules怎么處理。解析獲得CSS的技巧,是通過

      預加載/懶加載

      在設計上,一個子應用的資源有兩種可選加載形式。在麥飯中,假如你希望提前預加載子應用資源,可以在registerMicroApp時直接傳入 importSource(...),這個函數一執行,就會去請求資源回來并做緩存。但是,假如你不需要預加載,你想在子應用需要進入界面時(或打算讓子應用進入界面時)才加載資源,則配置為 () => importSource(...) ,這種配置會在子應用執行 bootstrap 的時候才去請求資源。

      環境隔離

      環境隔離是微前端框架實現時最核心的技術難點。由于子應用的開發團隊是分開的,兩個子應用之間,可能存在相互污染的問題,這就要求微前端框架實現一種能力,讓子應用運行在自己的一個隔離環境中,從而不對其他子應用造成污染。目前可以用來解決環境隔離的方案有:

      • iframe:樣式和腳本運行的隔離,缺點在于無法全屏彈出層
      • ShadowDOM:樣式隔離,缺點在于彈出層被掛在document.body下面,而樣式被放在ShadowDOM內部,無法正確渲染彈出層
      • 快照沙箱
      • 代理沙箱

      也有框架把這些方案結合起來,在不同的場景下,主動或被動的使用其中的一種方案。其中,快照沙箱和代理沙箱是兩種比較獨特的技術方案:

      快照沙箱

      多個子應用在頁面上相互切換,而子應用腳本運行會給當前全局環境帶來污染??煺丈诚溆糜诮鉀Q這種污染。這種方案只適合同一時間只運行一個子應用的場景,例如騰訊云控制臺。當子應用進入界面的時候,給window上的所有屬性打一個快照。子應用運行過程中window可能被修改。子應用離開界面時,把window清理干凈,再把快照上的屬性重新添加到window上,復原了子應用掛載前的window。

      代理沙箱

      代理沙箱解決一個頁面內同時運行多個子應用的場景。分兩個步驟實現:

      1. 創建代理對象

      比如上面提到window可能被污染。那就創建一個window的代理對象,例如fakeWin,實現如下:這樣處理之后,我們在讀取時可能讀取到原始window上的值,但是一旦我們寫入新屬性之后,再讀就讀到剛才寫入的值,但對于原始的window來說,沒有被污染。

      2. 創建運行沙箱

      要使代理對象作為全局對象給子應用的腳本使用,必須把子應用放在一個沙箱里面跑,這個沙箱使用我們制作的代理對象作為全局變量,這樣子應用的腳本就會操作代理對象,從而與其他子應用起到代理隔離的效果。具體實現如下:上面代碼里面的window, document, location等,都是前面創建好的代理對象。 當然,這里只給出了一些最核心思路的代碼,實際上在真正實現時,還要考慮各種特殊情況,需要進行多方面的處理。 通過代理沙箱,子應用就可以在主應用中獨立運行,而不會對主應用上的其他子應用產生負面影響。不過,值得一提的是,由于代理沙箱實際上虛擬了一個給子應用的環境來運行,也就意味著需要消耗更多的計算資源,會給子應用的性能帶來一定影響。同時,由于這種虛擬環境在某些情況下必須連接到真實環境進行操作,或者從另外一面反過來說,虛擬環境中不一定能提供子應用所需要的全部依賴,這就會導致子應用中某些功能失效,甚至影響整個子應用的表現效果。

      路由映射

      如果子應用有自己的路由系統,處理不好,子應用在切換路由時會污染父應用,導致瀏覽器url發生變化,結果把當前頁面切到另外一個地方去了。為了解決這種問題,麥飯實現了一個路由映射功能。因為子應用是運行在沙箱中的,所以,不同層的應用得到的location是不同的,基座應用使用瀏覽器的location,但是它的子應用則不是,修改瀏覽器的url之后,可以通過路由映射機制,偽造子應用得到的url。具體實現是通過創建一個臨時的iframe,利用代理沙箱的能力,將子應用的location代理到iframe里面的location上去。得益于代理沙箱,子應用的url變化不會導致瀏覽器的url變化。 映射邏輯需要寫一個map和reactive配置項,當瀏覽器的url發生變化時,通過map映射到子應用內部。子應用內部url發生變化時,通過reactive映射到瀏覽器,這樣即使用戶在某一時刻刷新瀏覽器,也可以通過url映射關系,準確還原子應用當前的界面。

      掛載

      在麥飯中,子應用需要通過一個標簽來決定子應用掛載在什么地方。和qiankun等框架不同,qiankun需要在子應用中決定掛載點,但是這可能造成沖突。麥飯的理念是子應用開發團隊不應該考慮自己應用的外部環境。所以,子應用在哪里掛載應該由父應用決定。 子應用被放在中,給了開發者一些特殊的能力:

      • 可以放在 v-if 內部,DOM節點被移除后掛回來,子應用還在
      • 動畫效果
      • keepAlive

      在實現時用到了一些比較 hack 的技巧。比如需要借助這個節點所在作用域的頂層節點,在頂層節點DOM對象上掛載一些數據,通過這個技巧,確保節點被移除后,再被掛載回來時,還能正確還原之前界面。 keepAlive則是在節點沒有被移除的情況下,子應用執行 unmount 時,并沒有實際銷毀子應用構建的 DOM 樹,而是放在內存中,當子應用再次 mount 的時候,直接把這個內存里面的 DOM 樹掛載到內部。

      通信/應用樹

      這部分是麥飯設計中最復雜的部分,也是最終與其他微前端框架區別的地方。我構建了一個這樣的樹狀數據結構,稱之為“應用樹”。它表達了基于 MFY 開發的微前端應用中,應用于子應用的引用關系。

      scope

      scope概念是指一個應用起來之后,會創建一個scope(作用域),這個 scope 保存了該應用的一些運行時信息,同時通過了通信的接口方法。一個應用可能會有多個子應用,這些子應用都有自己的 scope,上下級應用之間可以通過scope完成通信,比如 parent_app 可以給 child_app_1 和 child_app_2 下發一個指令,接到這個指令后,兩個子應用執行自己的邏輯。child_app_2 可以向 parent_app 發送一個指令,而 parent_app 再把這個指令轉發給了 child_app_1,這樣就完成了兩個子應用之間的通信。這像極了 react 組件通過 props 傳遞數據的模式。 rootScope 是一個特殊的scope,它對應的是基座應用,是應用樹的頂點。由于我把 scope 設計為可以廣播消息的訂閱/發布對象,所以,利用 rootScope 可以完成跨層應用間的直接通信(雖然不推薦)。

      connectScope

      每個應用通過connectScope連接到自己所在的scope。這里需要一些技巧才能實現,在同一層,實現邏輯有點像react hooks,你不需要關心你處于應用樹的哪個位置,對于子應用開發團隊而言,只需要在代碼中使用connectScope()函數,就可以直接連接到自己所在的作用域。如果你實現過react hooks的話,應該能理解它的一個實現原理。但是由于一些實現上的限制,你不能異步執行connectScope,必須在代碼第一次執行時,同步調用connectScope獲取當前子應用的scope。

      狀態共享

      “如果子應用1修改了用戶的某個狀態,子應用2怎么對這個修改做出響應?” 這個問題涉及到一個狀態共享問題。由于我在設計時,堅持每個子應用團隊應該封閉開發的理念,開發團隊不應該考慮自己開發的應用還會和其他應用放在一起使用,或者還需要依賴其他應用的狀態變化,這會讓我在開發的時候一直處于對當前應用狀態的未知狀態,那這樣就沒法調試和測試了。因此,設計中我直接拒絕實現子應用間的狀態共享。 但是在實際使用過程中,這種需求是存在的。因此,我建議使用通信的方式解決,子應用1發出一個消息,通過 rootScope,通知網絡我改變了用戶狀態,那么其他子應用在接受到這個消息之后,自己決定是否要重新渲染界面。

      思考

      本文雖然已經通過筆者實現麥飯這個小型微前端框架,詳細的闡述了一個微前端框架的核心技術實現,但是,也同時遺留了很多問題:

      • 跨域加載子應用問題
      • 子應用自己還要加載資源(angularjs模板)絕對路徑問題
      • 登錄態怎么傳遞?
      • 多語言怎么配置?
      • 代碼共享(依賴)怎么處理?
      • 運行時對象多個怎么辦?(例如每個子應用都有自己的jQuery)
      • 跨應用加載相同資源怎么辦?(例如同時請求一個api拉取數據)

      微前端不是萬能的,坑也很多,所以應了那句話“沒有銀彈”。

      結語

      微前端是一種架構形式,一旦采用這種架構,就會影響到你的應用的運行方式、團隊的管理方式、構建部署的方式,因此,開發團隊最好經過比較長一段時間的調研之后,才決定啟用這種架構。從本文中,你也會發現,要實現微前端框架的核心能力,需要使用一些看上去不那么優雅的hack方法,既然是hack方法,就存在一定的弊端,比較容易給將來的開發埋下坑。本文只介紹了實現微前端框架的核心技術點,在實際項目中,還需要面臨更多問題,但這并不是說我在勸退大家,而是希望大家在選擇時,根據實際的需求決定,不要由于這個很火就立馬使用。如果你對微前端相關的話題感興趣,可以在文章下面留言,我們一起探討有關微前端框架的實現技術。


      轉自:Tencent CDC(https://cdc.tencent.com/2022/02/22/micro-frontend-framework/)


      GO 欣賞案例
      查看經典案例

      TOP

      QQ客服

      電話咨詢

      QQ客服 微信咨詢 電話咨詢
      在線咨詢
       
      重要的事情,電話里聊

      接通客服

      不方便的時候線上咨詢,在線等哦