一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

前言

關注核心實現請直接跳至 第四小節:執行流程。

本文中的命令僅適用於支持shell的系統,如Mac、烏班圖及其他linux發行版。不適用於windows,如果想在windows下執行文章中的命令請使用git命令窗口(需安裝git)或linux子系統(win10以下不支持)。

一、初始化工程

1、初始化工程目錄

2、初始化npm環境

模塊說明:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

模塊說明

3、配置babel和rollup

創建babel.config.js

添加內容:

創建rollup.config.js

添加內容:

4、在package.json中添加script和browserslist字段

5、添加項目文件夾

到目前爲止,整個項目的文件夾結構應該是:

到此,項目就已經初始化完畢了,接下來開始核心的內容,微前端框架的編寫。

二、app相關概念

1、app要求

微前端的核心爲app,微前端的場景主要是:將應用拆分爲多個app加載,或將多個不同的應用當成app組合在一起加載。

爲了更好的約束app和行爲,要求每個app必須向外export完整的生命週期函數,使微前端框架可以更好地跟蹤和控制它們。

生命週期函數共有4個:bootstrap、mount、unmount、update。 生命週期可以傳入 返回Promise的函數也可以傳入 返回Promise函數的數組。

2、app狀態

爲了更好的管理app,特地給app增加了狀態,每個app共存在11個狀態,其中每個狀態的流轉圖如下:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

狀態說明(app和service在下表統稱爲app):

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

load、mount、unmount條件 判斷需要被加載(load)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

判斷需要被掛載(mount)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

判斷需要被卸載(unmount)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

3、app生命週期函數和超時的處理

app的生命週期函數何以傳入數組或函數,但是它們都必須返回一個Promise,爲了方便處理,所以我們會判斷:如果傳入的不是Array,就會用數組將傳入的函數包裹起來。

具體的流程如下圖所示:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

思考:如果用reduce的話怎麼寫?有什麼需要注意的問題麼?

爲了app的可用性,我們還講給每個app的生命週期函數增加超時的處理。

三、路由攔截

微前端中app分爲兩種:一種是根據Location進行變化的,稱之爲app。另一種是純功能(Feature)級別的,稱之爲service。

如果要實現隨Location的變化動態進行mount和unmount那些符合條件的app,我們就需要對瀏覽器的Location相關操作做統一的攔截。另外,爲了在使用Vue、React等視圖框架時降低衝突,我們需要保證微前端必須是第一個處理Location的相關事件,然後纔是Vue或React等框架的Router處理。

爲什麼Location改變時,微前端框架一定要第一個執行相關操作哪?如何保證"第一個"?

因爲微前端框架要根據Location來對app進行mount或unmount操作。然後app內部使用的Vue或React纔開始真正進行後續工作,這樣可以最大程度減少app內部Vue或React的無用(冗餘)操作。

對原生的Location相關事件進行攔截(hijack),統一由微前端框架進行控制,這樣就可以保證總是第一個執行。

四、執行流程(核心)

整個微前端框架的執行順序和js事件循環相似,大體執行流程如下:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

觸發時機

整個系統的觸發時機分爲兩類:

  • 瀏覽器觸發:瀏覽器Location發生改變,攔截onhashchange和onpopstate事件,並mock瀏覽器history的pushState()和replaceState()方法。
  • 手動觸發:手動調用框架的registerApplication()或start()方法。

修改隊列(changesQueue)

每通過觸發時機進行一次觸發操作,都會被存放到changesQueue隊列中,它就像事件循環的事件隊列一樣,靜靜地等待被處理。如果changesQueue爲空,則停止循環直至下一次觸發時機到來。

和js事件循環隊列不同的是,changesQueue是當前循環內的所有修改(changes)會綁成一批(batch)同時執行,而js事件循環是一個一個地執行。

"事件"循環

在每一次循環的開始階段,會先判斷整個微前端的框架是否已經啓動。

未啓動:根據規則(見上文的『判斷需要被加載(load)的App』)加載需要被加載的app,加載完成之後調用內部的finish方法。

已啓動:根據規則獲取當前因爲不滿足條件而需要被卸載(unmount)的app、需要被加載(load)的app以及需要被掛載(mount)的app,將load和mount的app先合併在一起進行去重,等unmout完成之後再統一進行mount。然後再等到mount執行完成之後就會調用內部的finish方法。

可以通過調用mySingleSpa.start()來啓動微前端框架。

通過上文我們可以發現不管是當前的微前端框架的狀態是未啓動或已啓動,最終都會調用內部的finish方法。其實,finish方法的內部很簡單,判斷當前的changesQueue是否爲空,如果不爲空則重新啓動下一次循環,如果爲空則終止終止循環,退出整個流程。

location事件

另外在每次循環終止時都會將已攔截的location事件進行觸發,這樣就可以保證上文說的微前端框架的location觸發時機總是首先被執行,而Vue或React的Router總是在後面執行。

最後

關於微前端框架倉庫地址如何獲取,首先關注我,並且私信我回復“教程”即可免費獲取!

如果你覺得本文對有幫助,記得點贊+轉發 分享給他人,看完不點讚的都是(流氓 /(ㄒoㄒ)/~~

對於本文你有其他的見解或想法歡迎評論區留言,謝謝!

關注核心實現請直接跳至 第四小節:執行流程。

本文中的命令僅適用於支持shell的系統,如Mac、烏班圖及其他linux發行版。不適用於windows,如果想在windows下執行文章中的命令請使用git命令窗口(需安裝git)或linux子系統(win10以下不支持)。

一、初始化工程

1、初始化工程目錄

2、初始化npm環境

模塊說明:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

模塊說明

3、配置babel和rollup

創建babel.config.js

添加內容:

創建rollup.config.js

添加內容:

4、在package.json中添加script和browserslist字段

5、添加項目文件夾

到目前爲止,整個項目的文件夾結構應該是:

到此,項目就已經初始化完畢了,接下來開始核心的內容,微前端框架的編寫。

二、app相關概念

1、app要求

微前端的核心爲app,微前端的場景主要是:將應用拆分爲多個app加載,或將多個不同的應用當成app組合在一起加載。

爲了更好的約束app和行爲,要求每個app必須向外export完整的生命週期函數,使微前端框架可以更好地跟蹤和控制它們。

生命週期函數共有4個:bootstrap、mount、unmount、update。 生命週期可以傳入 返回Promise的函數也可以傳入 返回Promise函數的數組。

2、app狀態

爲了更好的管理app,特地給app增加了狀態,每個app共存在11個狀態,其中每個狀態的流轉圖如下:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

狀態說明(app和service在下表統稱爲app):

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

load、mount、unmount條件 判斷需要被加載(load)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

判斷需要被掛載(mount)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

判斷需要被卸載(unmount)的App:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

3、app生命週期函數和超時的處理

app的生命週期函數何以傳入數組或函數,但是它們都必須返回一個Promise,爲了方便處理,所以我們會判斷:如果傳入的不是Array,就會用數組將傳入的函數包裹起來。

具體的流程如下圖所示:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

思考:如果用reduce的話怎麼寫?有什麼需要注意的問題麼?

爲了app的可用性,我們還講給每個app的生命週期函數增加超時的處理。

三、路由攔截

微前端中app分爲兩種:一種是根據Location進行變化的,稱之爲app。另一種是純功能(Feature)級別的,稱之爲service。

如果要實現隨Location的變化動態進行mount和unmount那些符合條件的app,我們就需要對瀏覽器的Location相關操作做統一的攔截。另外,爲了在使用Vue、React等視圖框架時降低衝突,我們需要保證微前端必須是第一個處理Location的相關事件,然後纔是Vue或React等框架的Router處理。

爲什麼Location改變時,微前端框架一定要第一個執行相關操作哪?如何保證"第一個"?

因爲微前端框架要根據Location來對app進行mount或unmount操作。然後app內部使用的Vue或React纔開始真正進行後續工作,這樣可以最大程度減少app內部Vue或React的無用(冗餘)操作。

對原生的Location相關事件進行攔截(hijack),統一由微前端框架進行控制,這樣就可以保證總是第一個執行。

四、執行流程(核心)

整個微前端框架的執行順序和js事件循環相似,大體執行流程如下:

一線大廠前端怎麼做?百度資深前端工程師,帶你手寫微前端框架

觸發時機

整個系統的觸發時機分爲兩類:

  • 瀏覽器觸發:瀏覽器Location發生改變,攔截onhashchange和onpopstate事件,並mock瀏覽器history的pushState()和replaceState()方法。
  • 手動觸發:手動調用框架的registerApplication()或start()方法。

修改隊列(changesQueue)

每通過觸發時機進行一次觸發操作,都會被存放到changesQueue隊列中,它就像事件循環的事件隊列一樣,靜靜地等待被處理。如果changesQueue爲空,則停止循環直至下一次觸發時機到來。

和js事件循環隊列不同的是,changesQueue是當前循環內的所有修改(changes)會綁成一批(batch)同時執行,而js事件循環是一個一個地執行。

"事件"循環

在每一次循環的開始階段,會先判斷整個微前端的框架是否已經啓動。

未啓動:根據規則(見上文的『判斷需要被加載(load)的App』)加載需要被加載的app,加載完成之後調用內部的finish方法。

已啓動:根據規則獲取當前因爲不滿足條件而需要被卸載(unmount)的app、需要被加載(load)的app以及需要被掛載(mount)的app,將load和mount的app先合併在一起進行去重,等unmout完成之後再統一進行mount。然後再等到mount執行完成之後就會調用內部的finish方法。

可以通過調用mySingleSpa.start()來啓動微前端框架。

通過上文我們可以發現不管是當前的微前端框架的狀態是未啓動或已啓動,最終都會調用內部的finish方法。其實,finish方法的內部很簡單,判斷當前的changesQueue是否爲空,如果不爲空則重新啓動下一次循環,如果爲空則終止終止循環,退出整個流程。

location事件

另外在每次循環終止時都會將已攔截的location事件進行觸發,這樣就可以保證上文說的微前端框架的location觸發時機總是首先被執行,而Vue或React的Router總是在後面執行。

最後

關於微前端框架倉庫地址如何獲取,關注公衆號:【fkdcxy,瘋狂的程序員丶】 即可免費獲取!

如果你覺得本文對有幫助,記得點贊+轉發 分享給他人,看完不點讚的都是(流氓 /(ㄒoㄒ)/~~

對於本文你有其他的見解或想法歡迎評論區留言,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章