《OneForAll框架搭建之旅》前端篇:微前端架構設計(Vue)
- 2020 年 3 月 4 日
- 筆記
心之所向,勇往直前!
記錄開發過程中的那些小事,給自己加點經驗值。
前言
作為一個.Net後端開發,在競爭愈加激烈的當下,掌握點前端配菜好像已經是家常便飯了。
剛好在工作的第5個年頭,辭去小主管職務的我要再次踏上面試之路,為了要避免被面試官吊打,除了複習《吊打面試官》相關的題目,當然也要對自己掌握的技能溫故知新。
項目使用了Vue cli3.0作為基礎架構,這個版本和2.0的有一些不同。具體參考:
環境
技術棧
上面是項目的一些基本情況,至於實際開發用到的組件這個每個人的項目都有可能不同,這裡就不貼出來了;而且這個系列只是對一些關鍵點進行記錄和說明,其他的在網上都可以找到資料的內容就不再重複。
架構
微服務這個詞可以說是大火特火,現在很多應用都在逐步朝着這方面轉移。
這個架構的好處,我想是不言而喻的。淺顯點理解就是獨立運行、靈活、擴展性強。
在調整後端架構的同時,我就想前端能不能也實現這種模式?在查找了幾天資料(主要參考《滴滴 webapp 5.0 Vue 2.0 重構經驗分享》)理清思路後,就抽出空餘的時間之後就搞出這一套架構。不過距離真正的微前端還是有些差距。畢竟現在前端的框架那麼多(Vue、React、Angular等等,如果要兼容每個框架,那麼可能會出現一些預加載組件出現冗餘,導致主頁加載緩慢。)
常見方案
- ifreame:簡單易實現,但冗餘html而且對SEO不友好
- WebComponents: 基本能實現功能,但兼容性不太行而且只對高版本瀏覽器有效(這是廢話,用了Vue已經放棄IE)
在這裡框架中我採用的以Vue為核心實現模塊化加載。
核心思路
主要通過一個中央處理器(可以理解為瀏覽器或者iframe)
處理器主要用於解析後端返回的模塊Url,根據地址發起Http請求拿到子模塊的index.html。這個文件的容量很小,但是裏面記錄了該模塊需要用到的css和js文件相對路徑。然後通過正則表達式解析出script標籤、style標籤。最後將標籤加載到主頁的最底部(利用瀏覽器自動加載文件的特性),完成了子模塊的Async加載。
子模塊擁有自己獨立的領域邏輯,組件,api接口文件(為了防止衝突,對命名有所規範)。各個模塊之間相互獨立,一般不會出現引用相同的插件的情況,造成項目冗餘。
如圖:
代碼:
reLoadWebsite (host, html) {
// 解析內容頁中的css/js引用,並插入父頁面文檔底部
let temp = []
let text = html
const page = { content: html, scripts: [], css: [] }
const regScript = /<script[s]+(?:[^>]+=[s]*[^>]+)*(?:src[s]*=[s]*['|"]?([^>]+(?:.js))['|"]?)></script>/i
while ((temp = regScript.exec(text)) != null) {
text = text.replace(temp[0], '')
if (temp[1] && temp[1].length > 0) page.scripts.push(host + temp[1])
}
const regCss = /<link[^>]+(?:href=['|"]?([^>]+(?:.css))['|"]?)[^>]*>/i
temp = []
text = html
while ((temp = regCss.exec(text)) != null) {
text = text.replace(temp[0], '')
if (temp[1] && temp[1].length > 0) page.css.push(host + temp[1])
}
this.loadCss(page.css)
this.loadScripts(page.scripts)
},
loadCss (css) {
var html = $('html').html()
for (var i = 0; i < css.length; i++) {
if (html.indexOf(css[i]) < 0) {
var link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = css[i]
document.body.appendChild(link)
}
}
},
loadScripts (scripts) {
var html = $('html').html()
for (var i = 0; i < scripts.length; i++) {
if (html.indexOf(scripts[i]) < 0) {
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = scripts[i]
document.body.appendChild(script)
}
}
},
路由裝載
主模塊中加載Vue-Router,先把一級路由創建出來。
然後在main.js中將Vue等公共對象暴露到window對象中,同時暴露一個registerChildRoutes方法,讓子模塊可以把獨立的路由註冊到主路由中。這樣就可是實現模塊化裝載的功能了。基本上到了這步,已經是簡單版的微前端框架。當然如果想要架構更加完整和堅固,還需要做更多的處理。
// 全局
const router = Router
const store = Store
window.Vue = Vue
window.AppData = {
Router,
Store,
Error,
registerChildRoutes: (routes) => {
const index = router.options.routes.find(w => w.name === INDEX.name)
if (index) {
routes.forEach(e => {
if (index.children.findIndex(w => w.name === e.name) < 0) {
index.children.push(e)
}
})
}
const newRouter = new VueRouter(router.options)
router.matcher = newRouter.matcher
}
}
結語
本篇到此結束,如果有任何疑問或者指正,請發表在評論區。
下一篇將講述《自動構建路由》,以及子模塊的接入