《OneForAll框架搭建之旅》前端篇:微前端架構設計(Vue)
心之所向,勇往直前!
記錄開發過程中的那些小事,給自己加點經驗值。
前言
作為一個.Net後端開發,在競爭愈加激烈的當下,掌握點前端配菜好像已經是家常便飯了。
剛好在工作的第5個年頭,辭去小主管職務的我要再次踏上面試之路,為了要避免被面試官吊打,除了複習《吊打面試官》相關的題目,當然也要對自己掌握的技能溫故知新。
專案使用了Vue cli3.0作為基礎架構,這個版本和2.0的有一些不同。具體參考:
1. 《vue cli3.0快速搭建專案詳解》
2. 《vue-cli2.0與vue-cli3.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
}
}
結語
本篇到此結束,如果有任何疑問或者指正,請發表在評論區。
下一篇將講述《自動構建路由》,以及子模組的接入