在 Web 開發導論/微前端與大前端一文中,筆者簡述了微服務與微前端的設計理念以及微前端的潛在可行方案。微服務與微前端,都是但願將某個單一的單體應用,轉化爲多個能夠獨立運行、獨立開發、獨立部署、獨立維護的服務或者應用的聚合,從而知足業務快速變化及分佈式多團隊並行開發的需求。如康威定律(Conway’s Law)所言,設計系統的組織,其產生的設計和架構等價於組織間的溝通結構;微服務與微前端不只僅是技術架構的變化,還包含了組織方式、溝通方式的變化。微服務與微前端原理和軟件工程,面向對象設計中的原理一樣相通,都是遵循單一職責(Single Responsibility)、關注分離(Separation of Concerns)、模塊化(Modularity)與分而治之(Divide & Conquer)等基本的原則。javascript
fe-boilerplates 是筆者的前端項目模板集錦,包含了單模塊單頁面、單模塊多頁面、(僞)多模塊單頁面、微前端項目等不一樣類型的模板,其中微前端項目模塊 m-fe/react-ts-webpack 與前者的區別即在於微前端中的各個模塊可以獨立開發,獨立版本發佈,獨立部署,獨立加載。分佈式協做勢必會帶來協同以及開發流程上的挑戰,在設計微前端項目架構的時候開發易用性也是很是重要的考量點。在年度總結中我也討論了使用 TS 面向重構編程的意義,歡迎參考 Backend-Boilerplates/node 中的 ts-*
項目,使用 TS 進行全棧開發。css
當咱們考量項目框架、模板或者腳手架的時候,首先想到的點就是但願儘量對上層屏蔽細節,可是對於長期維護的、多人協做的中大型項目而言,若是項目的主導者直接使用了部分抽象的腳手架,難免會給將來的更新、迭代帶來必定的技術負債;同時,目前也有不少成熟的工程化腳手架,所以筆者選擇以項目模板的形式抽象出微前端中所須要的部分。儘量地遵循簡約、直觀的原則,減小抽象/Magic Function 等;大型項目可能會抽象出專用的開發工具流,可是對於大部分項目而言,在現有框架/工具鏈的基礎上進行適當封裝會是較優選擇。html
# 拉取而且提取出子項目
git clone https://github.com/wxyyxc1992/fe-boilerplate
cp fe-boilerplate/micro-frontend/react-ts-webpack ../
# 添加全局的依賴更新工具
$ yarn global add npm-check-updates
# 爲各個子項目安裝依賴,以及連接各個子項目
$ npm run bootstrap && npm run build
# 執行預編譯操做
$ npm run build
# 以基礎模式運行 Host APP,此時 Host APP 做爲獨立應用啓動
$ cd packages/rtw-host-app & npm run dev:sa
# 以標準模式運行子應用
$ cd packages/rtw-mobx-app & npm run dev
# 返回根目錄
$ cd .. & npm start
複製代碼
值得說明的是,微前端做爲概念對於不一樣人承載了不一樣的考量,其實現方式、落地路徑也是見仁見智,如有不妥,敬請指教。前端
/[cdnHost]/[projectName]/[subAppName]/[x.y.z]/index.{js,css}
完整的微前端應用,可能會包含如下組成部分:java
基於此,咱們能夠將某個微前端應用抽象爲以下不一樣的模塊組:node
基礎模塊:react
核心模塊:webpack
子業務應用:git
擴展模塊:github
若是但願在子應用 A 中加載子應用 B 的實例,則應該使用相似於依賴注入的方式,從統一的註冊中心中獲取該實例對象。全部各個模塊共享的基礎庫,都必須以 UMD 模式加載到全局;rtw-host-app 中聲明與使用須要展現哪些模塊,rtw-bootstrap 中註冊可提供的 UMD 子模塊。
筆者一直推崇漸進式的工程架構,所以該模板對於複雜度要求較低的項目而言,能夠直接從基礎模式啓動,與其餘 TS 項目並沒有太大區別。
基礎模式相似於(僞)多模塊單頁面,僅有惟一的 Host APP 做爲編譯與運行的入口,其餘包體(譬如 rtw-core)直接打包進主包體中,不使用 SystemJS 進行獨立加載。
rtw-core
rtw-core 及類似的庫承載了公共的結構定義、工具類等,在該包體目錄下運行 npm run build
命令便可以生成 ES/CJS/UMD 等多種類型文件,以及 types 類型定義;能夠直接經過 npm publish 來發布到公共/私有的 NPM 倉庫中。
其餘包體經過 NPM 安裝 rtw-core 並使用,若是以標準模式運行,則須要首先加載該庫到全局做用域,利用 RequireJS/SystemJS 等工具遵循 AMD 規範來注入到其餘依賴的庫/應用中。
值得一提的是,對於子應用中,若是存在須要共享組件/類型的情景。對於類型信息,建議是將子應用一樣編譯打包發佈到 NPM 倉庫中,純組件能夠直接引入,對於業務組件建議經過全局的註冊中心來獲取。
rtw-host-app
在 rtw-host-app 包下,執行 npm run dev:sa
命令,會從 src/index.sa
文件啓動應用;如上文所述,該模式僅會基於 Webpack Splitted Chunk 進行異步加載,其開發流程與標準的單模塊應用並沒有區別。
rtw-bootstrap & rtw-host-app
rtw-bootstrap 是微前端應用的實際啓動點,其核心功能是執行依賴與子應用的註冊。在啓動時,其會根據傳入的 __HOST_APP__
與 __DEV_APP__
等變量信息完成應用的順序加載與啓動。在標準模式下,rtw-host-app 的入口是 src/index
文件,該模式下,index 文件會對外暴露 render 函數,該函數會由 rtw-bootstrap 注入 importApp 函數來執行子應用加載:
export function render(_importApp: Function) {
importApp = _importApp;
ReactDOM.render(
...
);
}
複製代碼
換言之,rtw-bootstrap 提供了應用加載的能力,而 rtw-host-app 決定了應該加載哪些應用;在實際案例中,咱們應該將用戶權限控制、菜單與子應用信息獲取等業務操做放置在 rtw-host-app 中。
rtw-redux-app & rtw-mobx-app
這裏以 rtw-mobx-app 爲例介紹如何進行子應用開發,若是是項目已經發布上線,那麼咱們能夠經過 Resource Overrides 等在線資源請求轉發的工具將線上資源請求轉發到本地服務器。在進行本地開發時,由於子應用自己並不會包含 ReactDOM.render
或者相似的將 Virtual DOM 渲染到界面的函數,所以在運行 npm run dev
以後,本地會開啓生成 UMD 文件的 Webpack Dev Server。參考子應用的 public/index.html
文件:
<script src="./bootstrap/static.js" type="text/javascript"></script>
<script src="./bootstrap/runtime.js" type="text/javascript"></script>
<script src="./bootstrap/vendors.js" type="text/javascript"></script>
<script> // 聯調環境 // window.__HOST_APP__ = { // id: 'host', // name: 'HOST APP', // module: 'http://0.0.0.0:8081/index.js', // css: 'http://0.0.0.0:8081/index.css' // }; // 正式開發環境 window.__HOST_APP__ = { title: 'HOST APP', module: '/release/rtw-host-app/index.js', css: '/release/rtw-host-app/index.css' }; window.__DEV_APP__ = { id: 'dev', name: 'DEV APP', module: '/index.js' }; </script>
<script src="./bootstrap/index.js" type="text/javascript"></script>
複製代碼
能夠看出子應用的啓動須要依賴於 rtw-bootstrap 以及 rtw-host-app,若是項目已經發布上線,那麼建議是直接從 CDN 加載資源;不然能夠將資源放置到 public/release
目錄下。若是本地須要同時調試 Host APP,則直接也將 Host APP 以開發方式運行(npm run dev
),而後直接引入 Webpack Dev Server 生成的資源地址便可。