目標是最完善的微前端解決方案- qiankun 2.0
Announcing [email protected]
2019年6月,微前端框架qiankun正式發布了1.0版本,在這一年不到的時間內,我們收穫了4k+ star,收穫了來自single-spa官方團隊的問候,支撐了阿里200+線上應用,也成為社區許多團隊選用的微前端解決方案。
在今天,qiankun 將正式發布2.0 版本。
[email protected]帶來了一些新能力的同時,只做了很小的API調整,1.x的用戶可以很輕鬆的遷移到2.x版本,詳細訊息見下方升級指南小節。
qiankun 簡介
可能有的朋友還不太了解微前端和qiankun 是什麼。
微前端是最近一年國內前端領域被頻繁提及的關鍵字,雖然它並不是一個全新的領域/技術,但很顯然在當今越來越多的前端應用即將步入第3 個、第5 個甚至更久的年頭的背景下,如何給巨石應用/遺產應用注入新鮮的技術血液已經成為我們不得不正視的問題,而微前端正是解決這類問題的一個非常合適的解決方案。
qiankun 是一個生產可用的微前端框架,它基於single-spa,具備js 沙箱、樣式隔離、HTML Loader、預加載等微前端系統所需的能力。 qiankun 可以用於任意js 框架,微應用接入像嵌入一個iframe 系統一樣簡單。
更多訊息可以查閱我們的官方站點
定位變化
qiankun 2.0帶來的最大變化便是qiankun的定位將由微前端框架轉變為微應用加載器。
此前qiankun 的典型應用場景是route-based 的控制台應用,做為一個微應用的聚合框架而被使用。
如上圖所示,在這種場景下,一個負責聚合與切換的主應用與多個相互獨自的微應用一起構成了整個大的微前端應用,一般來說頁面上同一時間活躍著的也往往只有一個微應用。
而這是微前端的場景之一,在另外一些場景下,你應該可以在同一個頁面中,加載多個不同的微應用,每個微應用都是主應用的組成部分或者是提供一些增強能力,這種場景可以說是微應用粒度的前端組件化。
因此,[email protected]將跳出route-based的微前端場景,提供更加通用的微應用加載能力,讓用戶可以更加自由的組合微應用來搭建產品。
本次升級帶來了什麼?
新功能
- 支持多應用並行及多實例沙箱
- 支持手動加載/卸載微應用
- 支持IE11 沙箱兼容
- 官方的極簡微應用通信方案
- 支持基於Shadow DOM 的樣式隔離
此外我們還做了
- 升級single-spa 到5.x 版本
- 更靈活的prefetch 的定制策略
- 配套的webpack 插件
- 更友好的部署場景支持,如自動為微應用注入運行時publicPath 等
- 更簡單易懂的API,重構了許多代碼,使其更清晰和更具擴展性
- 修復了一些bug
另外我們還升級了相應的umi qiankun plugin ,在umi場景下你可以這樣去加載一個微應用:
import { MicroApp } from 'umi'; function MyPage() { return ( <div> <MicroApp name="qiankun"/> </div> ); }
多應用支持
在[email protected] 中,我們的沙箱、樣式隔離等機制只能對單一微應用場景生效,多個微應用共存的支持能力尚不完備。
而在2.0 版本中,我們終於完善了這一功能,現在,你可以同時激活多個微應用,而微應用之間可以保持互不干擾。
在多應用場景下,每個微應用的沙箱都是相互隔離的,也就是說每個微應用對全局的影響都會局限在微應用自己的作用域內。比如A應用在window
上新增了個屬性test
,這個屬性只能在A應用自己的作用域通過window.test
獲取到,主應用或者其他微應用都無法拿到這個變量。
但是注意,頁面上不能同時顯示多個依賴於路由的微應用,因為瀏覽器只有一個url,如果有多個依賴路由的微應用同時被激活,那麼大概率會導致其中一個404。
為了更方便的同時裝載多個微應用,我們提供了一個全新的API loadMicroApp
,用於手動控制微應用:
import{loadMicroApp}from'qiankun';/** 手动加载一个微应用 */constmicroApp=loadMicroApp({name:"microApp",entry:"https://localhost:7001/micro-app.html",container:"#microApp"})// 手动卸载
microApp.mountPromise.then(()=>microApp.unmount());
這也是qiankun 作為一個應用加載器的使用方式。
基於這個api,你可以很容易的封裝一個自己的微應用容器組件,比如:
class MicroApp extends React.Component { microAppRef = null; componentDidMount() { const { name, entry } = this.props; this.microAppRef = loadMicroApp({ name, entry, container: '#container' }); } componentWillUnmount() { this.microAppRef.mountPromise.then(() => this.microAppRef.unmount()); } render() { return <div id="container"/>; } }
兼容IE11 的沙箱能力
在qiankun issue區域呼聲最高的就是IE的兼容,有不少小伙伴都期待qiankun能夠在IE下使用。
qiankun 1.x 在IE 使用的主要阻礙就是qiankun 的沙箱使用了ES6 的Proxy,而這無法通過ployfill 等方式彌補。這導致IE 下的qiankun 用戶無法開啟qiankun 的沙箱功能,導致js 隔離、樣式隔離這些能力都無法啟用。
為此,我們實現了一個IE 特供的快照沙箱,用於這些不支持Proxy 的瀏覽器;這不需要用戶手動開啟,在代理沙箱不支持的環境中,我們會自動降級到快照沙箱。
注意,由於快照沙箱不能做到互相之間的完全獨立,所以IE等環境下我們不支持多應用場景,
singlur
會被強制設為true。
基於shadow DOM 的樣式隔離
樣式隔離也是微前端面臨的一個重要問題,在[email protected] 中,我們支持了微應用之間的樣式隔離(僅沙箱開啟時生效),這尚存一些問題:
- 主子應用之間的樣式隔離依賴手動配置插件處理
- 多應用場景下微應用之間的樣式隔離亟待處理
為此,我們引入了一個新的選項, sandbox: { strictStyleIsolation?: boolean }
。
在該選項開啟的情況下,我們會以Shadow DOM 的形式嵌入微應用,以此來做到應用樣式的真正隔離:
import{loadMicroApp}from'qiankun'loadMicroApp({xxx},{sandbox:{strictStyleIsolation: true}});
Shadow DOM 可以做到樣式之間的真正隔離(而不是依賴分配前綴等約定式隔離),其形式如下:
圖片來自MDN
在開啟strictStyleIsolation
時,我們會將微應用插入到qiankun創建好的Shadow Tree中,微應用的樣式(包括動態插入的樣式)都會被掛載到這個Shadow Host節點下,因此微應用的樣式只會作用在Shadow Tree 內部,這樣就做到了樣式隔離。
但是開啟Shadow DOM 也會引發一些別的問題:
一個典型的問題是,一些組件可能會越過Shadow Boundary到外部Document Tree插入節點,而這部分節點的樣式就會丟失;比如antd的Modal
就會渲染節點至ducument.body
,引發樣式丟失;針對剛才的antd場景你可以通過他們提供的ConfigProvider.getPopupContainer
API來指定在Shadow Tree內部的節點為掛載節點,但另外一些其他的組件庫,或者你的一些代碼也會遇到同樣的問題,需要你額外留心。
此外Shadow DOM 場景下還會有一些額外的事件處理、邊界處理等問題,後續我們會逐步更新官方文檔指導用戶更順利的開啟Shadow DOM。
所以請根據實際情況來選擇是否開啟基於shadow DOM 的樣式隔離,並做好相應的檢查和處理。
官方的極簡通信方案
微前端場景下,我們認為最合理的通信方案是通過URL 及CustomEvent 來處理。但在一些簡單場景下,基於props 的方案會更直接便捷,因此我們為qiankun 用戶提供這樣一組API 來完成應用間的通信:
主應用創建共享狀態:
import{initGloabalState}from'qiankun';initGloabalState({user:'kuitos'});
微應用通過props 獲取共享狀態並監聽:
exportfunctionmount(props){props.onGlobalStateChange((state,prevState)=>{console.log(state,prevState);});};
更詳細的API介紹可以查看官方文檔。
我們會繼續為大家帶來什麼
除了基本的日常維護、bugfix 之外,我們還會嘗試走的更遠:
- 官方支持的qiankun webpack 插件,解決一些由於配置不當出現的問題
- 自定義的沙箱規則
- 微應用嵌套支持
- 更友好的調試體驗
- 與Webpack5 Module Federation 的結合,提供官方的使用指導或插件
- 更多的實驗性(experimental)嘗試,如基於原生Portal標籤的微應用渲染,基於運行時的更輕量的樣式隔離方案。
升級指南
2.0 版本調整了相當多的內部API 名字,但大家使用的外部API 變化並不大(基本完全兼容1.x),你可以在十分鐘內完成升級。
render 更改為container
import { registerMicroApps } from 'qiankun' registerMicroApps( [ { name: 'react16', entry: '//localhost:7100', - activeRule: location => location.pathname.startsWith('/react'), + activeRule: '/react', - render: renderFn, + container: '#subapp-viewport', }, ] )
現在你可以簡單的指定一個掛載節點即可,而不用自己手寫對應的render 函數了。簡單場景下activeRule
配置也不需要再手寫函數了(當然還是支持自定義函數),只需要給出一個前綴規則字符串即可,同時支持react-router類的動態規則,如/react/:appId/name
(來自single-spa 5.x的支持)。
同時,微應用收到的props
中會新增一個container
屬性,這就是你的掛載節點的DOM,這對處理動態添加的容器以及開啟了Shadow DOM場景下非常有用。
注意,舊的render 配置依然可以使用,我們做了兼容處理方便不想升級的用戶;但render 存在時,container 就不會生效。
start 的配置變化
因為我們引入了一些新的能力,因此start 的配置也發生了一些變化:
import { start } from 'qiankun' start({ - jsSandbox: true, + sandbox: { + strictStyleIsolation: true + } })
新的API loadMicroApp
這個API 用於手動掛載一個微應用
/** 用于加载一个微应用*/ loadMicroApp(app: LoadableApp, configuration?: FrameworkConfiguration)
使用詳情可見上面多應用支持小節。
最後
感謝qiankun 2.0開發過程中給予了大量支持的@小氫氣@茶山小旋風@斑馬世刺@dbkillerf6等同學,以及其他所有社區中幫助qiankun成長的更健壯的小伙伴們。
本文第一作者@小氫氣
最後的最後例行招聘:
螞蟻金服體驗技術部招聘前端啦!要求P6 及以上,上海、杭州、成都都有坑,有興趣的同學可以發簡歷到