這種微前端設計思惟據說過嗎?

圖怪獸_9bf9d9f09abbfa8d9c16825a02f88074_99081.jpg

前言:最近有種感受,好像微前端成爲當下前端工程師的標配,從single-spa到qiankun,各類微前端架構解決方案層出不窮。那一晚上,我在翻閱github時,留意到一個新的微前端框架,來自京東零售開源的MicroApp,號稱無需像上面提到那兩個框架同樣須要對子應用的渲染邏輯調整,甚至還不用修改webpack配置。還有一個成功引發我注意的是:它把web-components的概念給用上了!讓咱們一探究竟!css

1.飯後小菜 - Web Components 🍵

衆所周知,Web Components 是一種原生實現可服用web組件的方案,你能夠理解爲相似在vue、React這類框架下開發的組件。不一樣的是,基於這個標準下開發的組件能夠直接在html下使用,不用依賴其餘第三方的庫。html

換句話說:部分現代瀏覽器提供的API使咱們建立一個可複用的組件而無需依賴任何框架成爲一種可能,不會被框架所限制前端

主要包括如下幾個特徵:vue

  • 使用custom elements自定義標籤
  • 使用shadow DOM作樣式隔離
  • 使用 templates and slots 實現組件拓展 (本期不拓展)

那 Web Components是如何建立一個組件的?咱們來看下下面這個demo實踐node

1.1 實踐

針對web components的實踐, 我在github上找到一個demo。以下圖所示,假設一個頁面是由三個不一樣團隊負責獨立開發,A團隊負責紅色區域的總體展現功能,B團隊和C團隊分別負責藍色和綠色區域(在紅色區域內展現),那他們是怎麼實現的?webpack

image.png

咱們以綠色區域的功能爲示例,來看看demo的代碼實例,本質上能夠理解爲定義一個組件green-recosgit

carbon (27).png

經過上圖,咱們來分析這段代碼,主要包括如下幾點信息:github

  • 如何自定義元素?: 經過Api:window.customElements中的defind方法來定義註冊好的實例
  • 如何定義一個組件實例?: 經過繼承HTMLElement定義一個是實例類
  • 如何與外部通訊的?:經過建立一個CustomEvent來自定義一個新的事件,而後經過addEventListener來監聽以及element.dispatchEvent() 來分發事件
  • 如何控制組件的生命週期?: 主要是包括這幾個生命週期函數,順序以下 👇

constructor(元素初始化) -> attributeChangedCallback(當元素增長、刪除、修改自身屬性時,被調用) -> connectedCallback(當元素首次被插入文檔DOM時,被調用) -> disconnectedCallback(當 custom element從文檔DOM中刪除時,被調用)`web

拓展:面試

1.2 關於兼容性

👨‍🎓 啊樂同窗:樹醬,據說web component兼容性不太好?咋整?

image.png 你能夠看上圖👆 ,大部分瀏覽器新版本支持,若是想兼容舊版本,莫慌,能夠經過引入polyfill來解決兼容問題 webcomponents/polyfills

你也能夠經過堅挺WebComponentsReady這個事件來得知web components是否成功加載

1.3 關於樣式衝突

關於樣式,上面例子的樣式是全局引用的,並無解決樣式衝突的問題,那若是想基於Web Components 開發組件,又擔憂各組件間存在樣式衝突,這個時候你可使用Shadow DOM來解決,有點相似vue中定義組件中的scoped處理

Shadow DOM: 也稱影子DOM,它能夠將一個隱藏的、獨立的 DOM 附加到一個元素上。以下圖MDN官方介紹圖所示

image.png

那基於web component如何開發一個掛在#shadow-root的組件?

carbon (28).png

咱們能夠看到經過上圖對比上一節的例子,多了attachShadow的方法使用。它是啥玩意?

官方介紹:經過attachShadow來將一個 shadow root 附加到任何一個元素上。它接受一個配置對象做爲參數,該對象有一個 mode 屬性。當mode爲true,則表示能夠經過頁面內的 JavaScript 方法來獲取 Shadow DOM

🌲 擴展閱讀:

1.4 注意細節

啊樂同窗:樹君,那我在vue中可使用Web Component開發的自定義組件嗎?

能夠的,可是有一點要注意就是,Vue 組件開發很相似自定義元素,若是咱們不作點「手段」處理,vue會把你基於Web Component開發的組件看成自己框架下的組件來看待,so 咱們須要配置ignoredElements,下圖是vue官網的示例

image.png

若是想了解更多關於Web Component的組件開發,能夠看看下面這個開源的組件庫

2 Mrcio-app

一不當心繞遠了,言歸正傳,聊聊今日主角:micro-app

使用過qiankun的童鞋知道,咱們要在基座集成一個微應用離不開下面👇 這三要素:

  • 在基座註冊子應用
  • 須要在子應用定義好生命週期函數
  • 修改微應用的webpack打包方式

雖然改形成本不算特別高,可是能儘可能下降對源代碼的侵入性不香嗎?

Mrcio-app 走的就是極簡的路線,只要修改一丟丟代碼就能夠實現微應用的集成,號稱是目前市面上接入微前端成本最低的方案。那它是如何作到的?

2.1 原理

本質上 micro-app 是基於類WebComponent + HTML Entry實現的微前端架構

image.png

官方介紹:經過自定義元素micro-app的生命週期函數connectedCallback監聽元素被渲染,加載子應用的html並轉換爲DOM結構,遞歸查詢全部js和css等靜態資源並加載,設置元素隔離,攔截全部動態建立的script、link等標籤,提取標籤內容。將加載的js通過插件系統處理後放入沙箱中運行,對css資源進行樣式隔離,最後將格式化後的元素放入micro-app中,最終將micro-app元素渲染爲一個微前端的子應用。在渲染的過程當中,會執行開發者綁定的生命週期函數,用於進一步操做。

  • 關於HTML Entry:相信用過qiankun 的童鞋應該都很熟悉,就是加載微應用的入口文件,一方面對微應用的靜態資源js、CSS等文件進行fetch,一方面渲染微應用的dom

  • 類WebComponent: 咱們在上一節學習web Component中瞭解到兩個特徵:CustomElementShadowDom,前者使得咱們能夠建立自定義標籤,後者則促使咱們能夠建立支持隔離樣式和元素隔離的陰影DOM。而首次說起的類WebComponent是個啥玩意?本質上就是經過使用CustomElement結合自定義的ShadowDom實現WebComponent基本一致的功能

換句話說:讓微前端下微應用實現真正意義上的組件化

2.2 很讚的機制

micro-app 有這幾個機制我以爲很贊:

  • 不用像qiankun同樣在每一個微應用都預先定義好生命週期函數,如:createdmounted等,而是另闢蹊徑,當你在基座集成後,在基座能夠直接定義,也能夠進行全局監聽。以下所示

carbon (29).png

上圖的屬性配置中name是微應用的名稱配置,url是子應用頁面地址配置,其餘則是各個生命週期函數的定義

  • 資源地址自動補全:咱們在基座加載微應用的時候,當微應用涉及圖片或其餘資源加載時,若是訪問路徑是相對地址,咱們會發現會以基座應用所在域名地址補全靜態資源,致使資源加載錯誤。而micro-app支持將子應用靜態資源的相對地址補全爲絕對地址,解決了上述的問題

image.png

2.3 實踐

2.3.1 demo上手

上手也很簡單,以vue2應用爲例,具體參考 github文檔。這裏不作重複陳述

經過官方在線演示vue微應用Demo,咱們來看看集成後的效果

image.png

在控制檯咱們能夠看到,基座加載完微應用"vue2",在自定義標籤micro-app渲染後就是一個完整子應用Dom,有點相似iframe的感受,而後該子應用的css樣式,都多了一個前綴 micro-app[name=vue2]。這是利用標籤的name屬性爲每一個樣式添加前綴,將子應用的樣式影響禁錮在當前標籤區域,避免各個微應用之間的樣式衝突。這是micro-app的默認隔離機制

啊樂同窗:樹醬,他這個元素隔離是怎麼實現的?

你聽我解釋,看下一節源碼分析

2.3.2 渲染微應用的過程

渲染微應用的過程主要流程圖能夠參照官方提供,主要包括如下流程

image.png

  • fetch 子應用HTMl: 獲取html,而後轉換爲dom結構並遞歸處理每個子元素,對不一樣元素作相應的處理 源碼連接

目的是爲了提取微應用的link和script,綁定style做用域。最後實現將微應用的style掛在micro-app-head中 核心源碼以下 carbon (6).png

經過源碼的閱讀,當咱們在微應用的初始化定義的app.scopecss配置時(默認開啓),就會調用scopedCSS處理dom ,以此實現綁定微應用的css做用域,讓咱們看下這個方法的實現 源碼連接

我在源碼中看到scoped_css主要針對幾種cssRule來作區分處理

啊恆同窗:樹醬,什麼是Css Rule?

這是一個有歷史的概念了,CSSRule 表示一條 CSS 規則。而一個 CSS 樣式表包含了一組表示規則CSSRule對象。 CSSRule 有幾種不一樣的規則類型,你能夠在micro-app主要針對如下幾種常規的cssRule區分處理

  • CSSRule.STYLE_RULE: 通常的style規則
  • CSSRule.MEDIA_RULE: CSS @media 媒體屬性查詢的規則
  • CSSRule.SUPPORTS_RULE: CSS @support 能夠根據瀏覽器對CSS特性的支持狀況來定義不一樣的樣式的規則

carbon (7).png

最後將轉化成功的style內容,append到micro-app-head中

啊恆同窗:樹醬,你說micro-app隔離元素支持shadowDom ?

是的,若是開啓shadowDOM後,上面提到的默認的樣式隔離將失效。 且兼容性會比較差

下面是個刪減版:關於mircro-app經過Web Component + shadowDOM的實現子應用初始化的定義,具體的源碼你能夠閱讀框架源碼中關於micro_app_element的定義 源碼連接 carbon (8).png

本質上開啓shadowDom後,<micro-app>標籤纔算真正實現意義上的WebComponent

3 寫到最後

關於JS沙箱(sandbox)和數據通訊的實現機制等,在後面展開跟童鞋們分享

往期熱門文章📖:

你好,我是🌲 樹醬,請你喝杯🍵 記得三連哦~

1.閱讀完記得點個贊哦,有👍 有動力

2.關注公衆號前端那些趣事,陪你聊聊前端的趣事

3.文章收錄在Github frontendThings 感謝Star✨

相關文章
相關標籤/搜索