前言
最近幾年微前端一直是前端界的熱門議題, 它類似於微服務架構, 主要面向於瀏覽器端,能將一個複雜而龐大的單體應用拆分為多個功能模組清晰且獨立的子應用,且共同服於務同一個主應用。各個子應用可以獨立執行、獨立開發和獨立部署。
微前端架構概念的誕生及應用對於提供複雜應用服務的企業來說顯然是一種機遇, 同樣也是一種挑戰.本文主要就微前端架構的概念和實現方案做一個總結和覆盤,並且通過一個實際案例來實踐微前端架構,希望能對同樣有此需求的朋友們提供一些幫助和思路.
你將收穫
- 什麼是微服務以及微服務能給企業帶來什麼
- 微前端架構概念及方案
- umi下的微前端架構方案實戰
- 一個程式設計師的技術覆盤與展望
正文
在總結微前端架構之前,讓我們來先看看微服務是什麼.
1.什麼是微服務以及微服務能給企業帶來什麼
微服務是一種用於構建應用的架構方案。微服務架構有別於更為傳統的單體式方案,可將應用拆分成多個核心功能。每個功能都被稱為一項服務,可以單獨構建和部署,這意味著各項服務在工作(和出現故障)時不會相互影響。
傳統的web軟體開發架構往往如下圖所示:
雖然我們在傳統應用中可以採用模組化來拆分業務邏輯和開發方式,但最終它們會打包並部署為單體式應用。這種架構往往更適合中小型專案, 開發簡單直接,更適合集中化管理應用.但往往也會存在很多缺點,比如可擴充套件性不足,相同或者相似業務複用困難,部署時間長, 業務複雜之後很難維護等問題.對於複雜系統和業務來說,我們一般會採用微服務架構。其思路是將一個完整的應用分解為小的、互相連線的微服務,每個服務完成特定的功能, 並且某些特定的服務還能為其他服務提供API介面.
由上圖可以發現微服務給我們帶來的好處:- 將一個龐大的單體拆解成多個子服務,大大降低了開發複雜度
- 任務邊界劃分明確, 每個子服務之間單獨開發, 不同服務之間可並行由不同的開發人員開發,提高開發效率
- 更細粒度的加強了模組化程式, 可維護性和可讀性更高
- 團隊之間只要制定好API約定, 那麼不同成員或者團隊可以採用不同的技術開發服務
- 可用共享服務, 使得不同子服務可組合實現更復雜的功能
- 每個微服務可獨立部署釋出,使得自動化CI(持續整合)/CD(持續交付)成為可能
但微服務並不是任何場景下都是合適的, 微服務的目標是充分分解應用程式,以促進敏捷開發和持續整合部署。在部署微服務時我們需要做好適當的邊界劃分,並處理不同微服務之間的併發問題,這些都是對整個專案帶來的挑戰,需要更加專業的技術成員來把控.目前市面上也有很多開源的微服務框架比如Dubbo, Spring Cloud等,筆者之前公司採用的Spring Cloud就是一個很好的微服務架構方案.
2.微前端架構概念及方案
2.1 理解微前端架構
上面簡單介紹了一下微服務架構,接下來我們進入主題,來聊聊微前端. 微前端和微服務實現的目的類似,都是將應用由單一的單體應用轉變為多個小型子應用,差別就在於:
- 微前端應用於瀏覽器端,主要是對web應用進行拆解,最後將不同子系統(模組)聚合成一個完整的應用.
- 微前端主要目的是聚合,即將不同子系統聚合成一個大系統,而微服務架構目前更多是解耦,即解耦不同服務間的依賴.
我們先來看看微前端的一些思考者.
Michael Geers 大佬發表了一些對微前端的一些思考,內容大致總結一下就是:“ 微前端 ”是將微服務的概念擴充套件到前端領域。為了構建一個功能強大的瀏覽器應用程式(也稱為單頁應用程式),當前普遍的趨勢是將其建立在微服務架構之上。但是隨著時間的流逝,通常由獨立團隊開發的前端層會不斷增長,並且變得更加難以維護。Micro Frontends背後的想法是將Web應用程式視為由獨立團隊擁有的功能的組合。每個團隊都有自己關心和專長的不同業務或任務領域。每個團隊可以跨職能,並且從資料庫到使用者介面,端到端地開發其功能。
正如下面的例子所示:
當我們的系統中有多個不同的子模組,並且子模組之間有相對獨立且完整的功能體系時, 一旦子模組變得越來越多, 那麼整個應用將變得非常龐大且臃腫,開發和維護成本大大提高.如果在這種場景下我們採用SPA模式開發,那麼專案後期將變得不可想象,頁面首次載入將變得非常慢(筆者曾經就經歷過,開發一個複雜系統頁面首次載入花了20多秒,所以不得不採用MPA來處理); 但是我們採用MPA(多頁應用)模式,雖然解決了應用臃腫的問題, 但仍然存在很多有待處理問題,比如模組切換需要重新重新整理頁面, 公共元件無法共享,子模組直接,父子模組之間的通訊問題,開發部署繁瑣等.這寫都是傳統開發模式會遇到的問題.試想一下,如果面對以上問題, 如果有一種架構模式, 可以讓我們在主應用中共享公共元件和狀態(但是要保證子應用執行時內部的狀態隔離), 並且不同子模組之間可以單獨開發部署, 模組間切換不重新整理頁面, 並且模組之間,父子應用之間可以通過某種簡單的方式實現通訊,這樣是不是就完美了?不錯, 這也許就是微前端要解決的問題.
往往企業的中後臺系統更加適合使用微前端架構,因為B端大部分都是業務驅動,而往往這些業務之間會非常複雜, 比如Saas, Paas等系統.像類似於雲平臺,CRM,ERP系統往往是微前端架構的拯救物件.筆者曾經接手的ERP系統,由於開發時間比較早,往往有很多遺留的歷史包袱,比如新老技術棧的糅合, 前端業務程式碼龐大而毫無違和感,為了對其繼續迭代開發, 重構是必經之路,微前端另一個重要的作用筆者認為就是解放.解放不可挽回的痛?.
筆者之前在寫從0到1教你搭建前端團隊的元件系統(高階進階必備)這篇文章時簡單提了一下微前端的一些知識,這裡先回放一張筆者之前做的簡陋的圖,方便大家理解微前端架構.
但我們所看到的不是事實的全部,在文章後面筆者會總結一張更全面的圖,來整理微前端的一些實踐應用.2.2 微前端架構實現的方案
上面內容我們大致瞭解了一下微前端的概念和作用,接下來筆者總結一下曾經經歷過的微前端實現方案.
1. 基於MPA + iframe + requirejs實現的微前端架構 這是筆者接手最早的一個專案,主要是服務於企業內部的ERP系統,當時採用的技術棧主要是jquery+layui+requirejs,記得還是筆者剛畢業時參與的專案.主要是利用AMD模組化機制來複用程式碼,當時專案程式碼及其龐大複雜,大致架構如下:
傳統實現方式一般是通多多頁面的方式來對應用解耦,並採用模組化載入機制來匯入可複用元件.系統間通型採用storage+window.opener+iframe.比如我們一個大系統的首頁可能會有來自不同子系統的頁面,已iframe的方式嵌入.不同子系統間由不同的人維護,雖然做到了微前端的模式,但是還是有很多缺點. 改架構的一般分工是架構組主要負責制定架構標準和規範,維護公共模組(類似於現在的元件,當時由於採用jquery生態,可以簡單的說成公共UI外掛的維護);業務組主要負責編寫業務程式碼,實現某個系統的具體互動和功能。2. 基於MPA + iframe + Webpack實現的微前端架構 基於MPA + iframe + Webpack實現的微前端架構實現和上面介紹的傳統架構實現類似,只不過採用了更新的技術棧,以及真正的模組化,元件化技術。筆者之前做的Saas系統就是一個很典型的該方案的例子:
上圖可知不同子系統之間可以各自維護,單獨打包部署,最後通過node或者nginx做路由分發。我們採用公共的ui元件庫和js類庫來抽離公共元件,但是前提是不同元件庫和技術棧強相關,如果沒有歷史遺留的新專案,建議採用一致的技術棧。以上兩個方案的缺點就是元件庫只能複用而無法真正共享,並且切換路由會導致頁面重新渲染重新整理。父子系統通訊困難,仍然需要iframe最為容器來通訊。(有關iframe父子頁面通訊的各種方式筆者在記一次老專案中的跨頁面通訊問題和前端實現檔案下載功能)
3. 基umi + qiankun實現的微前端架構 目前市面上也有非常成熟的微前端架構方案,比如single-spa,之前的美團外賣微前端架構和螞蟻金服基於single-spa開發的微前端架構qiankun(乾坤),都是非常不錯的方案。
qiankun主要採用HTML Entry模式,直接將子應用打出來 HTML作為入口,主框架可以通過 fetch html 的方式獲取子應用的靜態資源,同時將 HTML document 作為子節點塞到主框架的容器中。這樣不僅可以極大的減少主應用的接入成本,子應用的開發方式及打包方式基本上也不需要調整,而且可以天然的解決子應用之間樣式隔離的問題。
其方案具有如下特點:- 支援子應用並行
- 支援js沙箱環境(js隔離)
- css隔離
- HTML Entry,簡化開發者使用
- 按需載入
- 公共依賴載入
- 父子應用通訊機制
- 子應用巢狀
因為我們的前端專案基於umi生態開發構建(之前採用webpack搭建,後面發現umi使用也很爽,就直接基於umi二次開發了),所以很自然的選擇了乾坤作為微前端架構。具體架構如下:
3.umi下的微前端架構方案實戰
接下來我具體介紹如何使用乾坤來搭建我們的微前端架構,由於我們內部採用umi,所以這裡我們直接使用其提供的@umijs/plugin-qiankun外掛來實現。(好處就是改動成本幾乎為零) 首先我們來實現這樣一個場景:我們有一個主應用作為基座工程,然後有3個子系統,他們是獨立建立維護的,可以採用不同的git倉庫來管理。當我們在主應用中切換路由時會切換到對應的子系統,且不重新整理頁面,完全的SPA體驗,接下來我們來具體實現一下吧。
這裡我們採用umi2.0來開發,關於如何安裝與使用umi,這裡就不做詳細介紹了。
- 建立工程
mkdir mainSystem subSystemA subSystemB subSystemC
// 分別進入各系統目錄下,執行以下命令建立我們的專案
yarn create umi
複製程式碼
- 在各個系統下安裝@umijs/plugin-qiankun外掛
yarn add @umijs/plugin-qiankun
複製程式碼
- 主應用下的配置
// .umirc.js
export default {
plugins: [
[
'@umijs/plugin-qiankun',
{
master: {
// 註冊子應用資訊
jsSandbox: true, // 是否啟用 js 沙箱,預設為 false
prefetch: true, // 是否啟用 prefetch 特性,預設為 true
},
},
],
],
};
// app.js
const isDev = process.env.NODE_ENV === 'development'
export const qiankun = {
apps: [
{
mountElementId: 'root-subapp-container', // 洗子應用掛載的節點
name: 'subSystemA', // 唯一 id,和package對應的name欄位最好保持一致
entry: isDev ? '//localhost:8001' : '/subSystemA/index.html', // html entry
base: '/subSystemA', 的路由字首,通過這個字首判斷是否要啟動該應用,通常跟子應用的 base 保持一致
history: 'browser', // 子應用的 history 配置,預設為當前主應用 history 配置
},
{
mountElementId: 'root-subapp-container',
name: 'subSystemB',
entry: isDev ? '//localhost:8002' : '/subSystemB/index.html',
base: '/subSystemB',
},
{
mountElementId: 'root-subapp-container',
name: 'subSystemC',
entry: isDev ? '//localhost:8003' : '/subSystemB/index.html',
base: '/subSystemC',
}
],
fetch: url => {
return fetch(url)
}
};
複製程式碼
以上是基本的配置,當然我們還可以在app.js裡面加入lifeCycles等鉤子來控制不同生命週期下的行為。
在子應用中我們同樣需要引入@umijs/plugin-qiankun這個外掛,具體配置如下:
export default {
base: `/${appName}`, // 子應用的 base,預設為 package.json 中的 name 欄位
plugins: ['@umijs/plugin-qiankun', { slave: true }],
};
複製程式碼
基本準備工作已經完成,剩下就是編寫業務程式碼了,我們要想讓整個應用一起跑起來,需要先啟動基座工程,然後再啟動對應的子工程(當然他們可以單獨執行)。
但是值得注意的是我們在開發環境中採用devServer提供的帶來才能跨域抓取資源,如果應用釋出到線上,如果不同子應用採用不同域名,我們還需要解決跨域問題(跨域解決的方案及安全機制也有很多,已經不再是個問題)。實際開發環境我們需要考慮的問題還有很多,這裡只做簡單介紹,不過根據官方提供的api基本上可以滿足大部分的需求場景,所以還是非常值得一試的。筆者後期也會寫一個微前端的實際案例釋出到github上,可以一起交流學習。
4.一個程式設計師的技術覆盤與展望
由於今年受疫情影響,工作任務比較緊張,覆盤的時間也比較少,但是筆者還是會堅持每週更新1-2篇文章,來總結和覆盤工作中或學到的新技術。自己寫的零零散散的文章是時候做一個分類和梳理,以便更加清晰未來的方向和不足的補救。
1.node相關
- 使用nodeJs開發自己的圖床應用
- 30分鐘帶你瞭解Web工程師必知的Docker知識
- 30分鐘教你優雅的搭建nodejs開發環境及目錄設計
- 基於nodeJS從0到1實現一個CMS全棧專案的服務端啟動細節
- 基於nodeJS從0到1實現一個CMS全棧專案(上)
- 基於nodeJS從0到1實現一個CMS全棧專案(中)(含原始碼)
- 基於nodeJS從0到1實現一個CMS全棧專案的服務端啟動細節
- 5分鐘教你用nodeJS手寫一個mock資料伺服器
2.工程化相關
- 前端元件/庫打包利器rollup使用與配置實戰
- 基於react/vue生態的前端整合解決方案探索與總結
- 9012教你如何使用gulp4開發專案腳手架
- vue/react專案中不可忽視的自動化部署方案
- 用 webpack 4.0 擼單頁/多頁尾手架 (jquery, react, vue, typescript)
- git常見用法和核心策略
3. 設計模式
- 15分鐘帶你瞭解前端工程師必知的javascript設計模式(附詳細思維導圖和原始碼)
- 《前端實戰總結》之使用直譯器模式實現獲取元素Xpath路徑的演算法
- 《前端實戰總結》之迭代器模式的N+1種應用場景
- 《前端實戰總結》之設計模式的應用——備忘錄模式
4.react相關
- 10分鐘教你手寫8個常用的自定義hooks
- 《徹底掌握redux》之開發一個任務管理平臺
- 從0到1教你搭建前端團隊的元件系統(高階進階必備)
- 精通React/Vue系列之實現一個全域性提示(Message)元件
- 精通React/Vue系列之手把手帶你實現一個功能強大的通知提醒框(Notification)
- 手摸手實現一個輕量級可擴充套件的模態框(Modal)元件
- 《精通react/vue元件設計》之5分鐘教你實現一個極具創意的載入(Loading)元件
- 《精通react/vue元件設計》之實現一個健壯的警告提示(Alert)元件
- 《精通react/vue元件設計》之配合React Portals實現一個功能強大的抽屜(Drawer)元件
- 《精通react/vue元件設計》之5分鐘實現一個Tag(標籤)元件和Empty(空狀態)元件
- 《精通react/vue元件設計》之快速實現一個可定製的進度條元件
- 《精通react/vue元件設計》之用純css打造類materialUI的按鈕點選動畫並封裝成react元件
- 基於jsoneditor二次封裝一個可實時預覽的json編輯器元件(react版)
5.vue/angular相關
- 從零到一教你基於vue開發一個元件庫
- 2年vue專案實戰經驗彙總
- 基於create-react-app打包編譯自己的第三方UI元件庫併發布到npm
- 一張圖教你快速玩轉vue-cli3
- 使用Angular8和百度地圖api開發《旅遊清單》
- vue高階進階系列——用typescript玩轉vue和vuex
6.css相關
- 《前端實戰總結》之使用純css實現網站換膚和焦點圖切換動畫
- 《前端實戰總結》之使用CSS3實現酷炫的3D旋轉透視
- 《css大法》之使用偽元素實現超實用的圖示庫(附原始碼)
- css3實戰彙總(附原始碼)
- 用css3實現驚豔面試官的背景即背景動畫(高階附原始碼)
- 如何把控css的方向感
7.演算法相關
- 如何優雅的使用javascript遞迴畫一棵結構樹
- 笛卡爾乘積的javascript版實現和應用
- JavaScript 中的二叉樹以及二叉搜尋樹的實現及應用
- js基本搜尋演算法實現與170萬條資料下的效能測試
- 《前端演算法系列》如何讓前端程式碼速度提高60倍
- 《前端演算法系列》陣列去重
8. H5遊戲
- 用60行程式碼實現一個高效能的聖誕抽抽樂H5小遊戲(含原始碼)
- Canvas入門實戰之用javascript物件導向實現一個圖形驗證碼
- 用 JavaScript 和 C3 實現一個轉盤小遊戲
- 教你用200行程式碼寫一個偶像拼拼樂H5小遊戲(附原始碼)
9.原生javascript類庫設計封裝
- 瀏覽器快取庫設計總結(localStorage/indexedDB)
- 基於 localStorage 實現一個具有過期時間的 DAO 庫
- 如何用不到200行程式碼寫一款屬於自己的js類庫
- 3分鐘教你用原生js實現具有進度監聽的檔案上傳預覽元件
10.工作問題彙總
- 5分鐘教你使用console.log釋出公司的招聘資訊
- 2019年,盤點一些我出過的前端面試題以及對求職者的建議
- 《前端實戰總結》之使用pace.js為你的網站新增載入進度條
- 《前端實戰總結》之使用postMessage實現可插拔的跨域聊天機器人
- 《前端實戰總結》之變數提升,函式宣告提升及變數作用域詳解
- 《前端實戰總結》如何在不重新整理頁面的情況下改變URL
- 快速掌握es6+新特性及es6核心語法盤點
- web效能優化的15條實用技巧
- 《javascript高階程式設計》核心知識總結
- 前端開發中79條不可忽視的知識點彙總
- 記一次老專案中的跨頁面通訊問題和前端實現檔案下載功能
- 讓你瞬間提高工作效率的常用js函式彙總(持續更新)
- 前端三年,談談最值得讀的5本書籍
最後
如果想學習更多H5遊戲, webpack,node,gulp,css3,javascript,nodeJS,canvas資料視覺化等前端知識和實戰,歡迎在公號《趣談前端》加入我們的技術群一起學習討論,共同探索前端的邊界。