Vite 微前端實(shí)踐,實(shí)現(xiàn)一個(gè)組件化的方案
微前端是一種多個(gè)團(tuán)隊(duì)通過(guò)獨(dú)立發(fā)布功能的方式來(lái)共同構(gòu)建現(xiàn)代化 web 應(yīng)用的技術(shù)手段及方法策略。
微前端借鑒了微服務(wù)的架構(gòu)理念,將一個(gè)龐大的前端應(yīng)用拆分為多個(gè)獨(dú)立靈活的小型應(yīng)用,每個(gè)應(yīng)用都可以獨(dú)立開發(fā)、獨(dú)立運(yùn)行、獨(dú)立部署,再將這些小型應(yīng)用聯(lián)合為一個(gè)完整的應(yīng)用。微前端既可以將多個(gè)項(xiàng)目融合為一,又可以減少項(xiàng)目之間的耦合,提升項(xiàng)目擴(kuò)展性,相比一整塊的前端倉(cāng)庫(kù),微前端架構(gòu)下的前端倉(cāng)庫(kù)傾向于更小更靈活。
特性
技術(shù)棧無(wú)關(guān) 主框架不限制接入應(yīng)用的技術(shù)棧,子應(yīng)用可自主選擇技術(shù)棧 獨(dú)立開發(fā)/部署 各個(gè)團(tuán)隊(duì)之間倉(cāng)庫(kù)獨(dú)立,單獨(dú)部署,互不依賴 增量升級(jí) 當(dāng)一個(gè)應(yīng)用龐大之后,技術(shù)升級(jí)或重構(gòu)相當(dāng)麻煩,而微應(yīng)用具備漸進(jìn)式升級(jí)的特性 獨(dú)立運(yùn)行時(shí) 微應(yīng)用之間運(yùn)行時(shí)互不依賴,有獨(dú)立的狀態(tài)管理 提升效率 應(yīng)用越龐大,越難以維護(hù),協(xié)作效率越低下。微應(yīng)用可以很好拆分,提升效率
目前可用的微前端方案
微前端的方案目前有以下幾種類型:
基于 iframe 完全隔離的方案
作為前端開發(fā),我們對(duì) iframe 已經(jīng)非常熟悉了,在一個(gè)應(yīng)用中可以獨(dú)立運(yùn)行另一個(gè)應(yīng)用。它具有顯著的優(yōu)點(diǎn):
非常簡(jiǎn)單,無(wú)需任何改造 完美隔離,JS、CSS 都是獨(dú)立的運(yùn)行環(huán)境 不限制使用,頁(yè)面上可以放多個(gè) iframe來(lái)組合業(yè)務(wù)
當(dāng)然,缺點(diǎn)也非常突出:
無(wú)法保持路由狀態(tài),刷新后路由狀態(tài)就丟失 完全的隔離導(dǎo)致與子應(yīng)用的交互變得極其困難 iframe中的彈窗無(wú)法突破其本身整個(gè)應(yīng)用全量資源加載,加載太慢
這些顯著的缺點(diǎn)也催生了其他方案的產(chǎn)生。
基于 single-spa 路由劫持方案
single-spa 通過(guò)劫持路由的方式來(lái)做子應(yīng)用之間的切換,但接入方式需要融合自身的路由,有一定的局限性。
qiankun 孵化自螞蟻金融科技基于微前端架構(gòu)的云產(chǎn)品統(tǒng)一接入平臺(tái)。它對(duì) single-spa 做了一層封裝。主要解決了 single-spa 的一些痛點(diǎn)和不足。通過(guò) import-html-entry 包解析 HTML 獲取資源路徑,然后對(duì)資源進(jìn)行解析、加載。
通過(guò)對(duì)執(zhí)行環(huán)境的修改,它實(shí)現(xiàn)了 JS 沙箱、樣式隔離 等特性。
京東 micro-app 方案
京東 micro-app 并沒(méi)有沿襲 single-spa 的思路,而是借鑒了 WebComponent 的思想,通過(guò) CustomElement 結(jié)合自定義的 ShadowDom,將微前端封裝成一個(gè)類 webComponents 組件,從而實(shí)現(xiàn)微前端的組件化渲染。
在 Vite 上使用微前端
我們從 我們從 UmiJS 遷移到了 Vite 之后,微前端也成為了勢(shì)在必行,當(dāng)時(shí)也調(diào)研了很多方案。
為什么沒(méi)用 qiankun
qiankun 是目前是社區(qū)主流微前端方案。它雖然很完善、流行,但最大的問(wèn)題就是不支持 Vite。它基于 import-html-entry 解析 HTML 來(lái)獲取資源,由于 qiankun 是通過(guò) eval 來(lái)執(zhí)行這些 js 的內(nèi)容,而 Vite 中的 script 標(biāo)簽類型是 type="module",里面包含 import/export 等模塊代碼, 所以會(huì)報(bào)錯(cuò):不允許在非 type="module" 的 script 里面使用 import。
退一步實(shí)現(xiàn),我們采用了 single-spa 的方式,并使用 systemjs 的方式進(jìn)行了微前端加載方案,也踩了不少的坑。single-spa 沒(méi)有一個(gè)友好的教程來(lái)接入,文檔雖然多,但大多都在講概念,當(dāng)時(shí)讓人覺(jué)得有一種深?yuàn)W的感覺(jué)。
后來(lái)看了它的源碼發(fā)現(xiàn),這都是些什么……里面大部分代碼都是圍繞路由劫持而展開的,根本沒(méi)有文檔上那種高大上的感覺(jué)。而我們又用不到它路由劫持的功能,那我們?yōu)槭裁匆盟?/p>
從組件化的層面來(lái)說(shuō) single-spa 這種方式實(shí)現(xiàn)得一點(diǎn)都不優(yōu)雅。
它劫持了路由,與 react-router和組件化的思維格格不入接入方式一大堆繁雜的配置 單實(shí)例的方案,即同一時(shí)刻,只有一個(gè)子應(yīng)用被展示
后來(lái)琢磨著 single-spa 的缺點(diǎn),我們可以自己實(shí)現(xiàn)一個(gè)組件化的微前端方案。
如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單、透明、組件化的方案
通過(guò)組件化思維實(shí)現(xiàn)一個(gè)微應(yīng)用非常簡(jiǎn)單:子應(yīng)用導(dǎo)出一個(gè)方法,主應(yīng)用加載子應(yīng)用并調(diào)用該方法,并傳入一個(gè) Element 節(jié)點(diǎn)參數(shù),子應(yīng)用得到該 Element 節(jié)點(diǎn),將本身的組件 appendChild 到 Element 節(jié)點(diǎn)上。

類型約定
在此之前我們需要約定一個(gè)主應(yīng)用與子應(yīng)用之間的一個(gè)交互方式。主要通過(guò)三個(gè)鉤子來(lái)保證應(yīng)用的正確執(zhí)行、更新、和卸載。
類型定義:
export interface AppConfig {
// 掛載
mount?: (props: unknown) => void;
// 更新
render?: (props: unknown) => ReactNode | void;
// 卸載
unmount?: () => void;
}
子應(yīng)用導(dǎo)出
通過(guò)類型的約定,我們可以將子應(yīng)用導(dǎo)出:mount、render、unmount 為主要鉤子。
React 子應(yīng)用實(shí)現(xiàn):
export default (container: HTMLElement) => {
let handleRender: (props: AppProps) => void;
// 包裹一個(gè)新的組件,用作更新處理
function Main(props: AppProps) {
const [state, setState] = React.useState(props);
// 將 setState 方法提取給 render 函數(shù)調(diào)用,保持父子應(yīng)用觸發(fā)更新
handleRender = setState;
return <App {...state} />;
}
return {
mount(props: AppProps) {
ReactDOM.render(<Main {...props} />, container);
},
render(props: AppProps) {
handleRender?.(props);
},
unmount() {
ReactDOM.unmountComponentAtNode(container);
},
};
};
Vue 子應(yīng)用實(shí)現(xiàn):
import { createApp } from 'vue';
import App from './App.vue';
export default (container: HTMLElement) => {
// 創(chuàng)建
const app = createApp(App);
return {
mount() {
// 裝載
app.mount(container);
},
unmount() {
// 卸載
app.unmount();
},
};
};
主應(yīng)用實(shí)現(xiàn)
React 實(shí)現(xiàn)
其核心代碼僅十余行,主要處理與子應(yīng)用交互 (為了易讀性,隱藏了錯(cuò)誤處理代碼):
export function MicroApp({ entry, ...props }: MicroAppProps) {
// 傳遞給子應(yīng)用的節(jié)點(diǎn)
const containerRef = useRef(null);
// 子應(yīng)用配置
const configRef = useRef();
useLayoutEffect(() => {
import(/* @vite-ignore */ entry).then((res) => {
// 將 div 傳給子應(yīng)用渲染
const config = res.default(containerRef.current);
// 調(diào)用子應(yīng)用的裝載方法
config.mount?.(props);
configRef.current = config;
});
return () => {
// 調(diào)用子應(yīng)用的卸載方法
configRef.current?.unmount?.();
configRef.current = undefined;
};
}, [entry]);
return <div ref={containerRef}>{configRef.current?.render?.(props)}div>;
}
完成,現(xiàn)在已經(jīng)實(shí)現(xiàn)了主應(yīng)用與子應(yīng)用的裝載、更新、卸載的操作?,F(xiàn)在,它是一個(gè)組件,可以同時(shí)渲染出多個(gè)不同的子應(yīng)用,這點(diǎn)就比 single-spa 優(yōu)雅很多。
entry 子應(yīng)用地址,當(dāng)然真實(shí)情況會(huì)根據(jù) dev 和 prod 模式給出不同的地址:
"micro-app" entry="http://localhost:3002/src/main.tsx" />
Vue 實(shí)現(xiàn)
不卡高清无码在线
|
WWW,色老板,C0m
|
天堂资源在线观看
|
影音先锋麻豆
|
中文字幕视频在线观看
|
