最近都在準備面試尤其是系統設計環節,因為面試的這個 position 比較偏全端所以平常什麼 scaling, load balancing, caching 等等都要知道一些,雖然本來就知道但得自己找題目練習一遍讓自己習慣在這樣的環境把這些思考邏輯弄好讓對方知道你在表達什麼和為什麼需要這些東西,如果這次有上那可能之後會有一集講如何準備 principal software engineer 的面試,如果沒上,那之後就會有一集講我如何fail 我的軟體工程師面試。
今天聊聊微前端,尤其是用 webpack module federation 為基礎架構的微前端,如果有聽過前面集數的人應該有聽過我小聊過微前端不過大部分是在鋪陳當時的話題比如 Nextjs 之類的,如果你有用過微服務 micro service 的話你會發現說每個 service 只 focus 在一個 function 比如這個管理 product data 這個管理 payment,然後每一個微服務可以單獨的 deploy、monitor、scaling等等,現在的 cloud provider 都把這些做好了,那這些微服務可以是 ECS instance 或是 Lambda function,反正重點就是可能因為你想要好測試、縮短部署的時間、減少整體的loading,所以選擇用微服務。
微前端大概就是類似的概念,對使用者來說這個前端 app 可能是一體的但對工程師來說每一頁或是極端一點每一個 component 可能是來自於不同的組,像我們公司是有各個不同的 micro app,每一個 app 都是獨立的,有自己的 repo、CICD pipeline、release schedule、等等而不用像是傳統的都在同一個 application 這樣。
從 high level 這樣看當使用者登入後會先下載一個 micro app 我們稱作為 shell app,這個 shell app會根據使用者的權限再去下載這個使用者可以看到且使用的其他 micro app,這些當然也是配合 API 來看我們可以下載什麼 applications,剩下的就是讓 module federation 去抓這些 JavaScript 然後跑起來。
剛剛一直提到的 module federation 是個 webpack 的 plugin,這個設定其實很簡單,最主要的就是:
At the end of the day, 這些 app 從使用者角度看都是同一個 app 但從 engineering 角度看每一頁可能都是不用的 micro app,也因為都有自己的 repo 自己的測試 pipeline deployment,每一個實質上都是獨立運作的。
這樣跟 npm package 有什麼不同,真的要說就是主動權吧,假設這些 micro app 都是npm package那只要我們的 shell app 沒有 npm install 最新的檔案那它永遠是舊的,因為 module federation 關係大家實際上是可以在自己想要的時間做部署這樣也會自動更新這些 micro app 也就不需要等其他 app 下載最新的 npm package 然後測試能不能跑能不能 build 這樣。
順帶提一下我們後端是 GraphQL server 而每一個組都可以有自己的 sub graph 最後 publish 到這個大的 Apollo gateway,每個組可能會為了一個micro app開一個sub graph這樣對應到那個app需要的queries 和 mutations,但如果gateway上面已經有你需要用的query就不用重新做一個了,這邊聽不懂沒關係總之就是微前端會叫一個可能只屬於自己的 API 然後後面會跟專門的微服務溝通。
我們這樣的系統已經兩年左右了,這邊列出幾個我覺得蠻大的缺點,不過這邊聲明有些缺點可能只是因為我們架構想錯了而導致的,或許別人的經驗會不一樣:
後來搜集意見和開會後決定之後這樣的架構會慢慢淘汰掉,取而代之就是透過 nginx 自定義不同的 route 然後分配這些 route 到不同的 application,這樣使用者進了特定的 path 就會到某個 app 這樣,就不會有之前的依賴性了,而我之前講的 Nextjs application 也是因為這樣新的架構而允許我們用不同的框架而不是綁死只能用 React做CSR。
其實這邊有些東西或許monorepo是可以解決的但感覺這跟人和文化有關,除非這些app都是自己的組的,要不然要大家從原本 multi-repo 移到 monorepo 這個挺困難的而且帶來的好處應該比這個 migration 的意願還要小很多
總之我大概沒事不會去碰 module federation 了