前言:最近有種感受,好像微前端成爲當下前端工程師的標配,從single-spa到qiankun,各類微前端架構解決方案層出不窮。那一晚上,我在翻閱github時,留意到一個新的微前端框架,來自京東零售開源的
MicroApp
,號稱無需像上面提到那兩個框架同樣須要對子應用的渲染邏輯調整,甚至還不用修改webpack配置。還有一個成功引發我注意的是:它把web-components的概念給用上了!讓咱們一探究竟!css
衆所周知,Web Components 是一種原生實現可服用web組件的方案,你能夠理解爲相似在vue、React這類框架下開發的組件。不一樣的是,基於這個標準下開發的組件能夠直接在html下使用,不用依賴其餘第三方的庫。html
換句話說:
部分現代瀏覽器提供的API使咱們建立一個可複用的組件而無需依賴任何框架成爲一種可能
,不會被框架所限制前端
主要包括如下幾個特徵:vue
那 Web Components是如何建立一個組件的?咱們來看下下面這個demo實踐node
針對
web components
的實踐, 我在github上找到一個demo。以下圖所示,假設一個頁面是由三個不一樣團隊負責獨立開發,A團隊負責紅色區域的總體展現功能,B團隊和C團隊分別負責藍色和綠色區域(在紅色區域內展現),那他們是怎麼實現的?webpack
咱們以綠色區域的功能爲示例,來看看demo的代碼實例,本質上能夠理解爲定義一個組件green-recos
git
經過上圖,咱們來分析這段代碼,主要包括如下幾點信息:github
window.customElements
中的defind方法來定義註冊好的實例HTMLElement
定義一個是實例類CustomEvent
來自定義一個新的事件,而後經過addEventListener
來監聽以及element.dispatchEvent()
來分發事件constructor(元素初始化) -> attributeChangedCallback(當元素增長、刪除、修改自身屬性時,被調用) -> connectedCallback(當元素首次被插入文檔DOM時,被調用) -> disconnectedCallback(當 custom element從文檔DOM中刪除時,被調用)`web
拓展:面試
👨🎓 啊樂同窗:樹醬,據說web component兼容性不太好?咋整?
你能夠看上圖👆 ,大部分瀏覽器新版本支持,若是想兼容舊版本,莫慌,能夠經過引入polyfill來解決兼容問題 webcomponents/polyfills
你也能夠經過堅挺WebComponentsReady
這個事件來得知web components是否成功加載
關於樣式,上面例子的樣式是全局引用的,並無解決樣式衝突的問題,那若是想基於Web Components 開發組件,又擔憂各組件間存在樣式衝突,這個時候你可使用Shadow DOM
來解決,有點相似vue中定義組件中的scoped處理
Shadow DOM: 也稱影子DOM,它能夠將一個隱藏的、獨立的 DOM 附加到一個元素上。以下圖MDN官方介紹圖所示
那基於web component如何開發一個掛在#shadow-root
的組件?
咱們能夠看到經過上圖對比上一節的例子,多了attachShadow
的方法使用。它是啥玩意?
官方介紹:經過attachShadow來將一個 shadow root 附加到任何一個元素上。它接受一個配置對象做爲參數,該對象有一個
mode
屬性。當mode爲true,則表示能夠經過頁面內的 JavaScript 方法來獲取 Shadow DOM
🌲 擴展閱讀:
啊樂同窗:樹君,那我在vue中可使用Web Component開發的自定義組件嗎?
能夠的,可是有一點要注意就是,Vue
組件開發很相似自定義元素,若是咱們不作點「手段」處理,vue會把你基於Web Component開發的組件看成自己框架下的組件來看待,so 咱們須要配置ignoredElements
,下圖是vue官網的示例
若是想了解更多關於Web Component的組件開發,能夠看看下面這個開源的組件庫
一不當心繞遠了,言歸正傳,聊聊今日主角:micro-app
使用過qiankun的童鞋知道,咱們要在基座集成一個微應用離不開下面👇 這三要素:
雖然改形成本不算特別高,可是能儘可能下降對源代碼的侵入性不香嗎?
Mrcio-app 走的就是極簡的路線,只要修改一丟丟代碼就能夠實現微應用的集成,號稱是目前市面上接入微前端成本最低的方案。那它是如何作到的?
本質上 micro-app 是基於類WebComponent + HTML Entry
實現的微前端架構
官方介紹:經過自定義元素
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中瞭解到兩個特徵:CustomElement
和 ShadowDom
,前者使得咱們能夠建立自定義標籤,後者則促使咱們能夠建立支持隔離樣式和元素隔離的陰影DOM。而首次說起的類WebComponent是個啥玩意?本質上就是經過使用CustomElement結合自定義的ShadowDom實現WebComponent基本一致的功能
換句話說:讓微前端下微應用實現真正意義上的組件化
micro-app 有這幾個機制我以爲很贊:
created
、mounted
等,而是另闢蹊徑,當你在基座集成後,在基座能夠直接定義,也能夠進行全局監聽。以下所示上圖的屬性配置中name是微應用的名稱配置,url是子應用頁面地址配置,其餘則是各個生命週期函數的定義
上手也很簡單,以vue2應用爲例,具體參考 github文檔。這裏不作重複陳述
經過官方在線演示vue微應用Demo,咱們來看看集成後的效果
在控制檯咱們能夠看到,基座加載完微應用"vue2",在自定義標籤micro-app
渲染後就是一個完整子應用Dom,有點相似iframe的感受,而後該子應用的css樣式,都多了一個前綴 micro-app[name=vue2]
。這是利用標籤的name
屬性爲每一個樣式添加前綴,將子應用的樣式影響禁錮在當前標籤區域,避免各個微應用之間的樣式衝突。這是micro-app的默認隔離機制
啊樂同窗:樹醬,他這個元素隔離是怎麼實現的?
你聽我解釋,看下一節源碼分析
渲染微應用的過程主要流程圖能夠參照官方提供,主要包括如下流程
目的是爲了提取微應用的link和script,綁定style做用域。最後實現將微應用的style掛在micro-app-head
中 核心源碼以下
經過源碼的閱讀,當咱們在微應用的初始化定義的app.scopecss
配置時(默認開啓),就會調用scopedCSS處理dom ,以此實現綁定微應用的css做用域,讓咱們看下這個方法的實現 源碼連接
我在源碼中看到scoped_css主要針對幾種cssRule
來作區分處理
啊恆同窗:樹醬,什麼是Css Rule?
這是一個有歷史的概念了,CSSRule
表示一條 CSS 規則。而一個 CSS 樣式表包含了一組表示規則CSSRule
對象。 CSSRule 有幾種不一樣的規則類型,你能夠在micro-app主要針對如下幾種常規的cssRule區分處理
@media
媒體屬性查詢的規則@support
能夠根據瀏覽器對CSS特性的支持狀況來定義不一樣的樣式的規則最後將轉化成功的style內容,append到micro-app-head中
啊恆同窗:樹醬,你說micro-app隔離元素支持shadowDom ?
是的,若是開啓shadowDOM
後,上面提到的默認的樣式隔離將失效。 且兼容性會比較差
下面是個刪減版:關於mircro-app經過Web Component + shadowDOM
的實現子應用初始化的定義,具體的源碼你能夠閱讀框架源碼中關於micro_app_element
的定義 源碼連接
本質上開啓shadowDom後,<micro-app>
標籤纔算真正實現意義上的WebComponent
關於JS沙箱(sandbox)和數據通訊的實現機制等,在後面展開跟童鞋們分享
往期熱門文章📖:
你好,我是🌲 樹醬,請你喝杯🍵 記得三連哦~
1.閱讀完記得點個贊哦,有👍 有動力
2.關注公衆號前端那些趣事,陪你聊聊前端的趣事
3.文章收錄在Github frontendThings 感謝Star✨