什麼是前端微服務,網上大把的介紹,我就不囉嗦了,簡單來講,就是把各個子項目整合到一塊兒。css
《前端架構:從入門到微前端》這本書中介紹,微前端架構通常能夠由如下幾種方式進行:html
其中比較常見的就是iframe
和single-spa
,這二者各有千秋。前端
頁面加載問題: 影響主頁面加載,阻塞onload
事件,自己加載也很慢,頁面緩存過多會致使電腦卡頓。(沒法解決)vue
佈局問題:iframe
必須給一個指定的高度,不然會塌陷。解決辦法:子系統實時計算高度並經過postMessage
發送給主頁面,主頁面動態設置高度,修改子系統或者代理插入腳本。有些狀況會出現多個滾動條,用戶體驗不佳。node
彈窗及遮罩層問題:只能在iframe
範圍內垂直水平居中,無法在整個頁面垂直水平居中。react
iframe
裏面的內容沒法實現佔滿屏幕的彈窗(非全屏),他只能在iframe範圍內全屏,沒法跳出iframe的限制在主頁面全屏,不過這種狀況也不多。瀏覽器前進/後退問題:iframe
和主頁面共用一個瀏覽歷史,iframe
會影響頁面的前進後退,大部分時候正常,iframe
屢次重定向則會致使瀏覽器的前進後退功能沒法正常使用,不是所有頁面都會出現,基本能夠忽略。可是iframe
頁面刷新會重置(好比說從列表頁跳轉到詳情頁,而後刷新,會返回到列表頁),由於瀏覽器的地址欄沒有變化。webpack
iframe
的頁面跳轉到其餘頁面出問題,好比兩個iframe
之間相互跳轉,直接跳轉會只在iframe
範圍內跳轉,因此必須經過主頁面來進行跳轉。不過iframe
跳轉的狀況不多ios
系統之間的通信須要經過postMessage
,存在必定的安全性git
css
和js
,避免了各個系統之間的樣式和js
污染css
和js
須要制定規範,進行隔離。不然容易形成全局污染,尤爲是vue
的全局組件,全局鉤子。document
。http
請求少,服務器壓力小。對比項 | single-spa | iframe | 補充 |
---|---|---|---|
加載速度 | single-spa能夠將全部系統共用的vue/vuex/vue-router等文件提取出來,只加載一次,各系統複用,加載速度很快,可是必須保證文件版本統一 | iframe會佔用主系統的http通道,影響主系統的加載,加載速度很慢 | 二者均可以經過http緩存提升必定的加載速度,可是對於vue這些通用文件無法作cdn,由於內部系統極可能沒法訪問外網 |
兼容性 | single-spa只適用於vue、react、angular編寫的系統,對一些jq寫的老系統無能爲力 | iframe則能夠嵌入任何頁面 | |
技術難度 | single-spa須要必定的技術儲備,有一些學習成本 | iframe門檻則很低,無需額外學習 | |
侷限性 | single-spa能夠嵌入任何部件 | iframe只能嵌入頁面,固然了也能夠把一個部件單獨寫成一個頁面 | |
改形成本 | single-spa必定要對子系統進行改造,可是改造的內容並很少不少,半小時便可完成 | iframe能夠不對原系統進行改造,可是必須藉助代理服務器進行插入腳本和css,增長了代理服務器也增長了系統的不穩定性(兩臺服務器中的任何一臺掛掉都會致使系統不可用),服務器也須要成本。如對原系統進行改造,則工做量和single-spa至關 | 項目的源文件丟失或者其餘一些沒法改動源文件的狀況,只能使用iframe |
補充:github
SEO
,iframe
沒法解決,可是single-spa
有辦法解決(谷歌能支持單頁應用的SEO
,百度則須要SSR
),可是內部系統,SEO的需求比較少。iframe
存在安全隱患,兩個iframe
頁面互相引用則會致使無限嵌套bug
,會致使頁面卡死,目前只能經過代理服務器檢查iframe
頁面內容來處理iframe很簡單,一個標籤就實現了。single-spa比較陌生,我會詳細介紹。
以vue
爲例,vue-cli4
生成的項目打包生成的index.html
文件內容以下(精簡了一些無關的內容):
<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>my-app</title>
<link href=/js/about.6b1cbb89.js rel=prefetch>
<link href=/css/app.c8c4d97c.css rel=preload as=style>
<link href=/js/app.6a6f1dda.js rel=preload as=script>
<link href=/js/chunk-vendors.164d8230.js rel=preload as=script>
<link href=/css/app.c8c4d97c.css rel=stylesheet>
</head>
<body>
<noscript>
<strong>We're sorry but my-app doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>
<div id=app></div>
<script src=/js/chunk-vendors.164d8230.js> </script>
<script src=/js/app.6a6f1dda.js> </script>
</body>
</html>
複製代碼
其中最核心的部分是:
<link href=/css/app.c8c4d97c.css rel=stylesheet>
<div id=app></div>
<script src=/js/chunk-vendors.164d8230.js> </script>
<script src=/js/app.6a6f1dda.js> </script>
複製代碼
猜測:可否藉助node
服務器,將子系統的index.html
獲取到,而後讀取HTML
,獲取到這幾個標籤,返回給主系統,主系統直接插入到body
中,可否呈現出子系統?
node
代理代碼實現,操做DOM
使用的是cheerio
插件:
const http = require('http')
// 引入cheerio模塊
const cheerio = require('cheerio')
const axios = require('axios')
const server = http.createServer(function (request, response) {
//請求子系統服務器,獲取到index.html文件
axios.get('http://localhost/').then(res => {
response.writeHead(200, {
'Content-Type': 'application/xml' ,
'Access-Control-Allow-Origin': '*'
})
// 加載HTML字符串
const $ = cheerio.load(res.data)
$('link').each(function () {
$(this).attr('href', 'http://localhost' + $(this).attr('href'))
})
$('script').each(function () {
$(this).attr('src', 'http://localhost' + $(this).attr('src'))
})
const resp = $('body').prepend($('link[rel=stylesheet]')).html();
response.end(resp)
}).catch(e => {
console.log(e)
})
})
server.listen(8080)
複製代碼
須要注意的是:
js/css
文件路徑都是相對路徑,須要拼上子項目的前綴。v-html
插入的DOM
片斷,外鏈script
不會生效,須要手動插入結果是主系統中#app
裏面能渲染出子系統,可是#app
裏面動態生成的HTML
,img/video/audio
等文件的路徑是相對的,因此會請求到主系統上,可是這些文件並不在主系統,因此會404,一樣,按需加載的路由頁面對應的js/css
文件也是相對路徑,會請求出錯。若是路由沒按需加載,則不存在這個問題
結論:能夠實現微服務效果,可是須要解決文件相對路徑的問題,index.html
裏面的link/script
還能夠手動加上,可是動態生成的html
裏面的img/video/audio
等,以及按需加載路由頁面對應的js/css
沒法經過代理服務器解決。
解決思路:
這裏面的js/css/img/video
等都是相對路徑,可否經過webpack
打包,將這些路徑所有打包成絕對路徑?這樣就能夠解決文件請求失敗的問題。
可否像CDN同樣,一個服務器掛了,會去其餘服務器上請求對應文件。或者說服務器之間的文件共享,主系統上的文件請求失敗會自動去子服務器上找到並返回。
可否手動(或藉助node
)將子系統的文件所有拷貝到主項目服務器上,node
監聽子系統文件有更新,就自動拷貝過來,而且按js/css/img
文件夾合併
查閱webpack
和vue-cli3
官網後發現:
默認狀況下,Vue CLI
會假設你的應用是被部署在一個域名的根路徑上,例如 https://www.my-app.com/
。若是應用被部署在一個子路徑上 https://www.my-app.com/my-app/
,而你使用的是history模式的路由,對於url:https://www.my-app.com/my-app/page1
,vue沒法區分my-app
是真實路徑,而page1
是路由參數,這個時候須要設置 publicPath
爲 /my-app/
,vue才能正確的請求文件資源和匹配路由。
這裏能夠將vue-cli3
的 publicPath
設置爲https://www.my-app.com/my-app/
,而後代碼裏面的js/css/img/video
路徑都會變成絕對路徑,前綴是https://www.my-app.com/my-app/
,這樣就解決了url
路徑的問題。
這樣就能夠實現一個簡單的single-spa
應用,可是加載好的Vue
子系統不會在切換到下一個系統的時候卸載掉,子系統過多則會致使卡頓,而且css/js
污染的可能性增長,實用性不大。
文章有什麼疑問or錯誤,歡迎評論。下一篇預告:從0實現一個single-spa
項目,包含完整的打包/開發調試流程,老項目如何改造等。