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