<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          探索微前端的場(chǎng)景極限

          共 9624字,需瀏覽 20分鐘

           ·

          2021-03-19 11:41

          點(diǎn)擊上方“程序員成長(zhǎng)指北,回復(fù)“1”進(jìn)交流群

          加入我們一起學(xué)習(xí),天天進(jìn)步

          本文由螞蟻金服體驗(yàn)技術(shù)部的 kuitos 授權(quán)轉(zhuǎn)發(fā),文中主要介紹總結(jié)了一些基于 qiankun 的微前端應(yīng)用場(chǎng)景與實(shí)踐,讓我們跟隨作者一起來領(lǐng)略微前端的魅力~

          基礎(chǔ)場(chǎng)景

          與路由綁定的方式渲染微應(yīng)用

          通常情況下,我們接觸的最多的微前端的實(shí)踐,是以 URL/路由 為維度來劃分我們的微應(yīng)用,以 OneX 平臺(tái)(螞蟻金融云基于微前端架構(gòu)打造的統(tǒng)一接入平臺(tái))為例:

          image.png

          接入這類平臺(tái)的微應(yīng)用,通常只需要提供自己的 entry html 地址,并為其分配一個(gè)路由規(guī)則即可。

          這背后的實(shí)現(xiàn)則是基于 qiankun 的 registerMicroApps API,如:

          import { registerMicroApps } from 'qiankun';

          registerMicroApps([
            {
              name'app1'
              container'#container'
              entry'//micro-app.alipay.com/'
              activeRule'/app1' 
            }
          ])

          路由與應(yīng)用綁定的方式簡(jiǎn)單直觀,是微前端中最為常見的使用場(chǎng)景,通常我們會(huì)用這種方式將一堆獨(dú)立域名訪問的 MPA 應(yīng)用,整合成一個(gè)一體化的 SPA 應(yīng)用。

          但這類場(chǎng)景也有自己的局限性:

          1. 由于URL/路由的 唯一性/排他性 的特點(diǎn),這種方式只適用單實(shí)例場(chǎng)景需求
          2. 微應(yīng)用的調(diào)度都是由路由系統(tǒng)來自動(dòng)處理的,雖然省事但是碰到更復(fù)雜的需求,如同一個(gè)路由下,根據(jù)不同的用戶權(quán)限展示不同的微應(yīng)用這類個(gè)性化訴求,需要寫一些中間層代碼來曲線救國(guó)
          3. 應(yīng)用掛載的容器節(jié)點(diǎn)等需提前準(zhǔn)備好,不然碰到 動(dòng)態(tài)/嵌套 路由這類情況,可能會(huì)因?yàn)槁酚?listener 監(jiān)聽觸發(fā)的時(shí)序不確定,導(dǎo)致微應(yīng)用無法完成掛載的問題

          以組件的方式使用微應(yīng)用

          qiankun 2.0 的發(fā)布帶來一個(gè)全新的 API loadMicroApp,通過這個(gè) API 我們可以自己去控制一個(gè)微應(yīng)用加載/卸載,這個(gè)方式也是 qiankun 2.0 的重磅特性:

          import { loadMicroApp } from 'qiankun';

          // do something

          const container = document.createElement('div');
          const microApp = loadMicroApp({ name'app', container, entry'//micro-app.alipay.com' });

          // do something and then unmount app
          microApp.unmout();

          // do something and then remount app
          microApp.mount();

          開發(fā)者可以在脫離路由的限制下,以更自由的方式去渲染我們的微應(yīng)用?;?loadMicroApp API,我們只需要做一些簡(jiǎn)單的封裝,即可以類似組件的開發(fā)體驗(yàn),完成微應(yīng)用的接入,以 React 為例:

          第一步:封裝一個(gè) MicroApp 組件:

          import { loadMicroApp } from 'qiankun';
          import React from 'react';

          export default class MicroApp extends React.Component {

            containerRef = React.createRef();
            microApp = null;

            componentDidMount() {
              const { name, entry, ...props } = this.props;
              this.microApp = loadMicroApp(
                { name, entry, containerthis.containerRef.current, props },
              );
            }

            componentWillUnmount() {
              this.microApp.unmount();
            }

            componentDidUpdate() {
              const { name, entry, ...props } = this.props;
              this.microApp.update(props);
            }

            render() {
              return <div ref={this.containerRef}></div>;
            }
          }

          第二步:通過 MicroApp 組件引入微應(yīng)用:

          import MicroApp from './MicroApp';
          import React from 'react';

          class App extends React.Component {
              render() {
              return (
                {
                  this.props.admin
                    ? <MicroApp name="admin" entry="http://localhost:8080/" level={10} />
                    : <MicroApp name="guest" entry="http://localhost:8081/" level={1} />
                }
              )
            }
          }

          如果你是 umi 應(yīng)用,那只需要直接使用插件封裝好的組件即可:

          import { MicroApp } from 'umi';

          function MyComponent({
            return (
              <div>
                <MicroApp name="qiankun" age={1.5} stars={8700} />
              </div>

            )
          }

          這類方式適用于一些可共用的、帶業(yè)務(wù)邏輯的服務(wù)型組件(類似于我們以前常說的端對(duì)端組件):比如帶聊天交互的客服機(jī)器人、帶引導(dǎo)功能的 intro 服務(wù)等。

          如螞蟻 sofa 產(chǎn)品控制臺(tái)中的這個(gè)使用入門微應(yīng)用:

          右側(cè)呼出的窗口即為一個(gè)獨(dú)立開發(fā)、獨(dú)立發(fā)布的微應(yīng)用

          通過組件的這種方式,我們可以完全自主的控制微應(yīng)用的渲染,并與之做一些復(fù)雜的交互。不論是在開發(fā)者的編碼心智,還是用戶的體驗(yàn)上,都跟使用一個(gè)普通的業(yè)務(wù)組件無異。

          組件的方式非常靈活,幾乎解決了所有路由綁定方式渲染微應(yīng)用的問題,但也有自己的一些局限:比如我們會(huì)要求這類微應(yīng)用必須是不帶路由系統(tǒng)的 widget 類型,不然也會(huì)出現(xiàn)多實(shí)例時(shí)路由沖突的問題。

          嵌套渲染場(chǎng)景

          有一些更復(fù)雜的場(chǎng)景中,我們可能需要使用到「套娃」的方式集成我們的若干微應(yīng)用。

          比如我們要在應(yīng)用 A 下集成應(yīng)用 B 的商品列表頁,然后在應(yīng)用 B 的商品列表頁呼出應(yīng)用 C 的買家詳情頁,所有應(yīng)用的喚起都以 彈層/抽屜 這種不刷新的交互來完成。

          在有了上面兩個(gè)場(chǎng)景的實(shí)踐經(jīng)驗(yàn)后,我們很容易得出這樣的組合邏輯:

          在應(yīng)用 A 中通過調(diào)用 loadMicroApp(B) 的方式喚起微應(yīng)用 B,然后在微應(yīng)用 B 中通過 loadMicroApp(C) 的方式喚起微應(yīng)用 C,通過這樣的調(diào)用鏈路即可很完美的完成產(chǎn)品上的訴求。

          但是現(xiàn)實(shí)情況往往沒有那么簡(jiǎn)單,前面提到過,若想要 loadMicroApp API 能符合預(yù)期的運(yùn)行,我們需要確保被加載的微應(yīng)用是不含自己的路由系統(tǒng),否則會(huì)出現(xiàn)多個(gè)應(yīng)用間路由系統(tǒng)互相 搶占/沖突 的情況。

          而現(xiàn)實(shí)情況是,我們大部分需要復(fù)用的頁面/組件,都會(huì)是某個(gè)站點(diǎn)的局部路由頁,很少有人會(huì)專門起一個(gè)倉(cāng)庫(kù),用來專門把這個(gè)頁面抽取成一個(gè)微應(yīng)用,比如上面提到的買家詳情頁。

          這種場(chǎng)景下,我們其實(shí)只需要確保微應(yīng)用的路由系統(tǒng)不會(huì)干擾到全局的 URL 系統(tǒng)即可。幸運(yùn)的是 react-router 的 memory history 模式很好的解決了這一問題。如果你是一個(gè) umi 應(yīng)用,只需要直接使用我們封裝好的組件即可完成 memory history 的運(yùn)行時(shí)切換:

          import { MicroAppWithMemoHistory } from 'umi';

          <Drawer>
            <MicroAppWithMemoHistory name="buyer" url='/buyers/123' />
          </Drawer>

          交互效果可以參考:

          視頻中 app1/app2 均是子應(yīng)用,但是在 app1 中可以再通過抽屜呼出 app2,同時(shí)瀏覽器地址欄也不會(huì)被 app2 的路由干擾。

          關(guān)于嵌套渲染相關(guān)的詳細(xì)介紹,可以看這篇《基于微前端的大型中臺(tái)項(xiàng)目融合方案》

          極限渲染場(chǎng)景

          如果你覺得嵌套微應(yīng)用就是我們場(chǎng)景的天花板了,那未免有點(diǎn)小看群眾們的想象力了。

          在我們內(nèi)部的一個(gè)設(shè)計(jì)工程化平臺(tái)里,我們通過 qiankun 成功的把一個(gè)微應(yīng)用的 20+ 路由頁同時(shí)渲染到了一個(gè) url 下:

          image.png

          上圖中右側(cè)列表中每一個(gè) demo 都是通過 qiankun 渲染的一個(gè)獨(dú)立微應(yīng)用實(shí)例,而這里面每一個(gè)微應(yīng)用實(shí)例,實(shí)際對(duì)應(yīng)是同一個(gè) react 應(yīng)用的不同路由頁。

          不同于前面幾個(gè)場(chǎng)景,將同一個(gè)應(yīng)用的不同頁面,同時(shí)渲染到主應(yīng)用的不同 UI 容器中這個(gè)需求下,有幾個(gè)比較特殊的問題需要去考慮:

          1. 是否需要特殊的微應(yīng)用生產(chǎn)方式
          2. 多路由系統(tǒng)共存帶來的 沖突/搶占 問題
          3. 不同微應(yīng)用間的樣式隔離
          4. 如何優(yōu)化渲染性能:既然每一個(gè)微應(yīng)用實(shí)例實(shí)際對(duì)應(yīng)的是同一個(gè)應(yīng)用,那我們?nèi)绾伪M可能多的復(fù)用一些運(yùn)行時(shí)或者沙箱,從而降低這么多微應(yīng)用同時(shí)渲染代理的運(yùn)行時(shí)開銷

          篇幅考慮,針對(duì)這類場(chǎng)景優(yōu)化的技術(shù)細(xì)節(jié)不在這里介紹了,后面會(huì)單獨(dú)寫一篇來介紹

          解決了這些問題后,我們只需要在我們的項(xiàng)目中這么去使用就可以了:

          // MicroAppWithMemoHistory 是基于 memory history 封裝的微應(yīng)用加載器
          import { MicroAppWithMemoHistory } from 'umi';

          function Home {
            return (
              <div>
                { /* 將同一個(gè)應(yīng)用的不同路由頁同時(shí)渲染出來 */ }
                <MicroAppWithMemoHistory name="demo" url="/demo1" />
                <MicroAppWithMemoHistory name="demo" url="/demo2" />
                <MicroAppWithMemoHistory name="demo" url="/demo3" />
                <MicroAppWithMemoHistory name="demo" url="/demo4" />
                <MicroAppWithMemoHistory name="demo" url="/demo5" />
                <MicroAppWithMemoHistory name="demo" url="/demo6" />
              </div>

            )
          }

          更多的想象空間

          工程上的想象空間

          微前端架構(gòu)除了其帶來的巨石應(yīng)用解構(gòu)、技術(shù)棧無關(guān)等工程能力外,也為我們對(duì)一些已有的工程問題帶來了新的解題思路,比如:

          npm 包分發(fā)業(yè)務(wù)組件背后的工程問題

          在以前,我們經(jīng)常通過發(fā)布 npm 包的方式復(fù)用/共享我們的業(yè)務(wù)組件,但這種方式存在幾個(gè)明顯的問題:

          1. npm 包的更新下發(fā)需要依賴產(chǎn)品重新部署才會(huì)生效
          2. 時(shí)間一長(zhǎng)就容易出現(xiàn)依賴產(chǎn)品版本割裂導(dǎo)致的體驗(yàn)不一致
          3. 無法灰度
          4. 技術(shù)棧耦合

          說白了就是 npm 包這種靜態(tài)的共享方式,喪失了動(dòng)態(tài)下發(fā)代碼的能力,導(dǎo)致了其過慢的工程響應(yīng)速度,這在現(xiàn)在云服務(wù)流行的時(shí)代就會(huì)顯得格外扎眼。而微前端這種純動(dòng)態(tài)的服務(wù)依賴方式,恰好能方便的解決上面的問題:被依賴的微應(yīng)用更新后的產(chǎn)物,在產(chǎn)品刷新后即可動(dòng)態(tài)的獲取到,如果我們?cè)谖?yīng)用加載器中再輔以灰度邏輯,那么動(dòng)態(tài)更新帶來的變更風(fēng)險(xiǎn)也能得到有效的控制。

          新的 UI 共享模式

          在以前,如果我們希望復(fù)用一個(gè)站點(diǎn)的局部 UI,幾乎只有這樣一條路徑:從業(yè)務(wù)系統(tǒng)中抽取出一個(gè)組件 -> 發(fā)布 npm 包 -> 調(diào)用方使用 npm 包。

          且不說前面提到的 npm 自身的問題,單單是從一個(gè)已有的業(yè)務(wù)系統(tǒng)中抽取出一個(gè) UI 組件這個(gè)事情,都可能夠我們喝一壺的了。我們不僅要在物理層面,將這部分代碼抽取成若干個(gè)單獨(dú)的文件,同時(shí)還要考慮如何跟已有的系統(tǒng)做上下文解耦,這類工作出現(xiàn)在一個(gè)越是年代久遠(yuǎn)的項(xiàng)目上,實(shí)施起來就越是困難,做過這類事情的同學(xué)應(yīng)該都會(huì)深有體會(huì)。

          不同于組件庫(kù)的研發(fā)流程,微前端的場(chǎng)景下,大部分時(shí)候我們不會(huì)為了去復(fù)用一個(gè) UI,而去專門寫一個(gè)微應(yīng)用出來。通常我們期望的是,從一個(gè)已有系統(tǒng)中,直接選取我們需要復(fù)用的部分,嵌入到我們自己的容器里進(jìn)行渲染。

          基于上面提到過的微應(yīng)用多實(shí)例的渲染方案,我們可以考慮將需要復(fù)用的組件,以路由 URL 作為 ID 的方式導(dǎo)出。比如我們有這樣一個(gè) A 應(yīng)用有一個(gè)這樣的頁面:

          function OnePage({
            return (
              <div>
                <SearchForm/>
                <UserList/>
              </div>

            )
          }

          我們有另外一個(gè)應(yīng)用,希望單獨(dú)復(fù)用 A 應(yīng)用的用戶列表部分的交互跟 UI,那我們只需要多加一條路由規(guī)則:

          <Switch>
            ...
            <Route path="/userList" memory={true}>
              <UserList/>
            </Route>
          </
          Switch>

          依賴方只需要配合 memory history 并指定 url 為 /userList 即可完成渲染(參考上面嵌套渲染章節(jié))。

          站點(diǎn)即配置

          當(dāng)我們將所有可以共享的服務(wù)單元變成一個(gè)個(gè)獨(dú)立的微應(yīng)用之后,我們便可以通過配置的方式描述我們的站點(diǎn)了,類似:

          {
            layout'admin-pro',
            apps: [
              { name'abc'props: {} },
              { name'bcd'props: {} },
              { name'cde'props: {} },
            ]
          }

          其中 layout 可以是一個(gè)帶基礎(chǔ)交互框架、用戶鑒權(quán)等公共能力的微應(yīng)用,也可以是一組微應(yīng)用的集合(類似 babel 中的 preset 插件),而 apps 則是一組需要在當(dāng)前站點(diǎn)渲染出來的業(yè)務(wù)微應(yīng)用。

          這種方式非常適用于,當(dāng)我們要在一個(gè)業(yè)務(wù)域下開發(fā)多個(gè)細(xì)分服務(wù)站點(diǎn)時(shí),通過這種配置的方式,配合一個(gè)運(yùn)行時(shí)的微應(yīng)用編排引擎,快速的生成一系列視覺一致、交互統(tǒng)一的業(yè)務(wù)站點(diǎn)出來。

          產(chǎn)品上的想象空間

          在有了上面那些場(chǎng)景背后的技術(shù)支撐后,在產(chǎn)品上,我們就已經(jīng)多出很多想象空間了。

          但我們還可以想的更極限一點(diǎn):

          比如我們知道微信有一個(gè)公眾號(hào)浮窗的功能,包括安卓系統(tǒng)常見的小窗模式,解決的就是空間獨(dú)占、以及跨空間時(shí)的交互問題。

          image.png

          那我們?cè)谥泻笈_(tái)也可以參考類似的設(shè)計(jì),將不同空間的關(guān)聯(lián)性操作以這種非獨(dú)占的形態(tài)聚合到一起,從而降低流程上的斷層感,提升產(chǎn)品體驗(yàn)。

          demo.jpg

          (這里本有一張螞蟻內(nèi)部系統(tǒng)的交互示意圖,因涉及保密信息無法公開,有興趣的同學(xué)可以選擇加入我們后做進(jìn)一步的交流分享??)

          寫在最后

          微前端提供的這些漸進(jìn)式更新、動(dòng)態(tài)組合、 服務(wù)拓展的能力,相信大家通過我們介紹的這些常見場(chǎng)景,以及一些極致條件下的解決方案中能窺其一二。

          但需要強(qiáng)調(diào)的是,任何技術(shù)架構(gòu)都不可能是銀彈,我們不必對(duì)微前端過于神化/劣化。本篇僅希望在分享了我們?cè)谖⑶岸祟I(lǐng)域的一系列探索之后,能給其他開發(fā)者帶來一些新的選擇和啟發(fā),從而為其工程及產(chǎn)品上帶來更多的可能性。

          最后的最后,誠(chéng)招天下英雄

          上面提到的這些案例,包括一些想象中的場(chǎng)景,正在我們團(tuán)隊(duì)內(nèi)有條不紊地發(fā)生著,只是時(shí)機(jī)未到還不能更詳細(xì)的對(duì)外宣傳并與大家分享,歡迎有興趣的同學(xué)可以加入我們,與我們一起去探索更多微前端的可能性。

          如果您對(duì)微前端感興趣,請(qǐng)發(fā)簡(jiǎn)歷到 [email protected],我們非常期望有機(jī)會(huì)能與您共事,探索出微前端下更多的場(chǎng)景可能性。

          如果您對(duì)微前端沒什么興趣,不要緊,只需要您對(duì) antd、AntV、dva、umi、eggjs、ahooks 中任一類別的領(lǐng)域感興趣,您也可以發(fā)簡(jiǎn)歷到 [email protected] 來與我們共商大事。

          團(tuán)隊(duì)介紹

          • 大部門:螞蟻集團(tuán)體驗(yàn)技術(shù)部
          • 部門主管:玉伯
          • 部門開源作品:antd、AntV、dva、umi、eggjs、qiankun、ahooks 等
          • 部門商業(yè)化產(chǎn)品:語雀
          • 直屬部門:平臺(tái)前端技術(shù)部 - 部門主管:偏右(antd 負(fù)責(zé)人),部門介紹:https://www.yuque.com/afx/about/skyline
          • 要求:基本沒要求,p5~p8 我們都需要,只要您想來試試就可以投簡(jiǎn)歷到 [email protected],HC 非常多?。?/section>
          • base 地:杭州、上海、成都 三地任選

          關(guān)注我們

          我們將為你帶來最前沿的前端資訊。

          ??愛心三連擊

          1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的點(diǎn)贊,在看是我創(chuàng)作的動(dòng)力。

          2.關(guān)注公眾號(hào)程序員成長(zhǎng)指北,回復(fù)「1」加入高級(jí)前端交流群!「在這里有好多 前端 開發(fā)者,會(huì)討論 前端 Node 知識(shí),互相學(xué)習(xí)」!

          3.也可添加微信【ikoala520】,一起成長(zhǎng)。

          “在看轉(zhuǎn)發(fā)”是最大的支持


          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天躁日日躁狠狠躁欧美男男 | 全国男人的天堂网站 | 外网成人网站 | 九七在线视频 | 九一免费观看网站 |