用)
前端微前端【免費(fèi)下載鏈接】qiankun Blazing fast, simple and complete solution for micro frontends.項(xiàng)目地址https://gitcode.com/gh_mirrors/qi/qiankun點(diǎn)擊查看免費(fèi)下載qiankunjs/react是 qiankun 官方提供的 React 生態(tài)綁定包它把loadMicroApp封裝成一個(gè)聲明式的MicroApp組件讓宿主應(yīng)用可以在 React 組件樹中像使用普通組件一樣掛載、更新和卸載微應(yīng)用并額外提供了用于路由導(dǎo)航的MicroAppLink。讀完本文你將掌握這兩個(gè)組件的全部用法安裝、Props 傳遞、加載態(tài)與錯(cuò)誤邊界、通過 ref 獲取運(yùn)行實(shí)例、settings與lifeCycles配置以及它們底層如何與 qiankun 的 Parcel 生命周期協(xié)同工作。安裝與環(huán)境要求npm install qiankunjs/reactrc qiankunrcqiankunjs/react的 peer dependencies 為qiankun^3.0.0-rc.15、react與react-dom均要求16.9.0。從 package.json 可以看到包本身依賴qiankunjs/ui-shared承載 React/Vue 兩個(gè)綁定共用的掛載、更新、卸載邏輯和lodash用于 props 的深比較同時(shí)以 workspace 方式將qiankun作為開發(fā)依賴確保綁定與核心運(yùn)行時(shí)版本一致。構(gòu)建產(chǎn)物同時(shí)提供 ESMdist/esm與 CJSdist/cjs入口并聲明sideEffects: false便于打包器做 tree-shaking。組件定位聲明式掛載而非全局注冊(cè)MicroApp適合這樣的場(chǎng)景宿主本身是 React SPA你希望在某個(gè)路由頁面、某個(gè)面板或彈層中把微應(yīng)用當(dāng)作一個(gè)普通組件放進(jìn)去而不是通過registerMicroApps將其注冊(cè)為跟隨 URL 自動(dòng)激活的全局應(yīng)用。二者都是官方推薦的掛載方式區(qū)別在于registerMicroAppsstart由 URL 驅(qū)動(dòng)激活規(guī)則activeRule而MicroApp由宿主組件自身的生命周期驅(qū)動(dòng)。若你需要同時(shí)運(yùn)行多個(gè)微應(yīng)用實(shí)例可參考同時(shí)運(yùn)行多個(gè)微應(yīng)用實(shí)例。用MicroAppLink做宿主路由導(dǎo)航MicroAppLink是為通過registerMicroApps注冊(cè)的微應(yīng)用提供的宿主導(dǎo)航鏈接宿主完成注冊(cè)并調(diào)用start之后點(diǎn)擊鏈接會(huì)經(jīng)由 single-spa 的navigateToUrl改變 URL由注冊(cè)的activeRule決定哪些微應(yīng)用掛載或卸載。鏈接本身不會(huì)加載任何微應(yīng)用。import { MicroAppLink, type MicroAppLinkProps } from qiankunjs/react; import { useRef } from react; export default function Navigation() { const linkRef useRefHTMLAnchorElement(null); const appLink: MicroAppLinkProps { to: /app1, className: nav-link, activeClassName: is-active, }; return ( nav MicroAppLink {...appLink} ref{linkRef}App one/MicroAppLink MicroAppLink to/app2/settings replaceApp two settings/MicroAppLink /nav ); }Props 一覽Prop類型說明tostring必填。目標(biāo) URL渲染為鏈接的href。replaceboolean是否替換當(dāng)前歷史記錄條目。默認(rèn)false導(dǎo)航時(shí)新增一條歷史記錄。classNamestring鏈接的 CSS 類。activeClassNamestring當(dāng)當(dāng)前 URL 匹配目標(biāo) URL 前綴時(shí)追加的 CSS 類。默認(rèn)不追加任何類。childrenReactNode鏈接內(nèi)容。refRefHTMLAnchorElement指向渲染出的a元素。MicroAppLinkProps從包入口導(dǎo)出。除了組件自身消費(fèi)的屬性外原生a屬性target、rel、download、aria-*、data-*、事件處理器等都會(huì)被透?jìng)鞯絘元素上to提供href。點(diǎn)擊攔截規(guī)則組件會(huì)先調(diào)用你傳入的onClick隨后僅在滿足全部條件時(shí)才攔截導(dǎo)航事件未被preventDefault()取消是左鍵點(diǎn)擊button 0未按下 Ctrl / Meta / Shift / Alt 修飾鍵實(shí)際生效的target為空或_self省略target時(shí)遵循頁面base target的設(shè)置鏈接為同源origin 一致的 HTTP(S) 鏈接且沒有download屬性。以上任一條件不滿足外部鏈接、下載鏈接、新標(biāo)簽頁、修飾鍵點(diǎn)擊都保留瀏覽器原生行為。滿足條件時(shí)若設(shè)置replace組件使用history.replaceState并派發(fā)popstate通知路由監(jiān)聽器否則走navigateToUrl。這一判定邏輯實(shí)現(xiàn)在 shared/link.ts 的navigateMicroAppLink中replaceUrl還做了巧妙的處理先用事件監(jiān)聽器對(duì)象探測(cè) single-spa 是否已同步處理本次replaceState若沒有收到通知再手動(dòng)補(bǔ)發(fā)popstate避免重復(fù)觸發(fā)路由事件。高亮匹配規(guī)則activeClassName的匹配是字符串前綴比較不解析路由參數(shù)組件解析目標(biāo) URL把pathname search hash與當(dāng)前 URL 的對(duì)應(yīng)字符串做前綴比較實(shí)現(xiàn)見isMicroAppLinkActiveshared/link.ts。因此to/app1同時(shí)匹配/app1/settings和/app10to/匹配所有路徑to中的查詢參數(shù)與 hash 參與同樣的前綴比較。若需要精確匹配宿主可自行設(shè)置className和aria-current。組件通過訂閱popstate、hashchange、single-spa:routing-event三個(gè)事件見subscribeToMicroAppLinkLocation來保持高亮狀態(tài)與瀏覽器導(dǎo)航、single-spa 路由重排同步并在訂閱前后各讀取一次window.location.href以彌合渲染到監(jiān)聽器安裝之間的導(dǎo)航窗口?;居梅∕icroApp唯一必填的 props 是name和entry其中entry是微應(yīng)用 HTML 入口的 URLimport { MicroApp } from qiankunjs/react; export default function Page() { return MicroApp nameapp1 entryhttp://localhost:8000 /; }組件渲染一個(gè)容器div把微應(yīng)用掛載進(jìn)該容器當(dāng)組件卸載時(shí)微應(yīng)用隨之卸載。??name 和 entry 必填若name或entry缺失組件僅打印the name and entry of MicroApp is needed并什么都不做——不會(huì)拋異常。請(qǐng)務(wù)必同時(shí)傳入兩者。該日志來自 shared/index.ts 中mountMicroApp的守衛(wèi)分支。Props 總覽與保留字段組件的 Props 類型定義如下見 MicroApp.tsximport { type MicroApp } from qiankun; // 導(dǎo)出組件類型 type Props SharedProps SharedSlotsReact.ReactNode Recordstring, unknown;末尾的Recordstring, unknown是有意為之任何不屬于保留 props 的屬性都會(huì)被原樣轉(zhuǎn)發(fā)給微應(yīng)用成為它的 props。這里沒有單獨(dú)的appProps——額外 props 本身就是微應(yīng)用的 props這與 Vue 版本通過專門的appProps對(duì)象傳遞有所區(qū)別詳見 Vue 版MicroApp組件。保留 propsProp類型默認(rèn)值說明name*string—該微應(yīng)用實(shí)例的名稱。更改它會(huì)卸載當(dāng)前實(shí)例并創(chuàng)建新實(shí)例。entry*string—微應(yīng)用的 HTML 入口 URL。settingsAppConfiguration—透?jìng)鹘oloadMicroApp的加載器 / 沙箱配置。lifeCyclesLifeCycles—宿主為該實(shí)例提供的生命周期鉤子如beforeLoad、beforeMount。autoSetLoadingbooleanfalse渲染內(nèi)置加載指示器并在應(yīng)用掛載完成后自動(dòng)清除。autoCaptureErrorbooleanfalse渲染內(nèi)置錯(cuò)誤邊界而非把加載錯(cuò)誤向外拋出。wrapperClassNamestring—追加到包裝元素上的類。僅在加載器或錯(cuò)誤邊界激活時(shí)生效。classNamestring—追加到掛載容器元素上的類。loader(loading: boolean) ReactNode—自定義加載 UI 的 render-prop 插槽。errorBoundary(error: Error) ReactNode—自定義錯(cuò)誤 UI 的 render-prop 插槽。* 必填。??保留字段不會(huì)被轉(zhuǎn)發(fā)組件消費(fèi)的所有屬性——name、entry、settings、lifeCycles、autoSetLoading、autoCaptureError、loader、errorBoundary、wrapperClassName、className——會(huì)被組件剝除不會(huì)到達(dá)微應(yīng)用。這一剝除邏輯在 shared/index.ts 的componentOwnedProps列表與omitSharedProps中實(shí)現(xiàn)注釋特別說明了為什么要?jiǎng)兂秩静宀蹆?nèi)聯(lián)loader每次宿主渲染都是新函數(shù)若泄漏給微應(yīng)用會(huì)破壞 props 的深比較。向微應(yīng)用傳遞 props任何非保留 prop 都會(huì)被轉(zhuǎn)發(fā)給微應(yīng)用并送達(dá)其bootstrap/mount/update生命周期MicroApp nameapp1 entryhttp://localhost:8000 // 以下都會(huì)被轉(zhuǎn)發(fā)給微應(yīng)用作為 props userId{42} themedark onEvent{(e) console.log(e)} /在微應(yīng)用內(nèi)部這些值出現(xiàn)在每個(gè)生命周期的props上export async function mount(props) { console.log(props.userId, props.theme); }當(dāng)這些 props 變化時(shí)組件用 lodash 的isEqual做深比較見 MicroApp.tsx 的useDeepCompare若發(fā)生變化則對(duì)運(yùn)行中的應(yīng)用調(diào)用microApp.update(props)——不會(huì)重新掛載。更新只在應(yīng)用狀態(tài)為MOUNTED時(shí)真正執(zhí)行。重掛載 vs 原地更新更改name會(huì)卸載當(dāng)前實(shí)例并創(chuàng)建新實(shí)例。更改其他轉(zhuǎn)發(fā) prop 只嘗試原地update。單獨(dú)更改entry、settings或lifeCycles不會(huì)創(chuàng)建新實(shí)例。若要徹底重置請(qǐng)更改name或給組件一個(gè)新的key。更新機(jī)制的實(shí)現(xiàn)細(xì)節(jié)updateMicroAppshared/index.ts并非簡(jiǎn)單調(diào)用microApp.update而是維護(hù)了一條串行鏈?zhǔn)状胃乱詍ountPromise為起點(diǎn)確保更新發(fā)生在掛載完成之后——這里只能補(bǔ)上起點(diǎn)不能跳過本次更新否則宿主傳入的第一次 props 變更會(huì)被吞掉后續(xù)更新通過_updatingPromise鏈?zhǔn)酱?lián)保證更新順序與組件狀態(tài)變更順序一致且后一個(gè)更新必須等待前一個(gè)完成更新前檢查app.update存在、狀態(tài)為MOUNTED且未被標(biāo)記為_unmounting避免更新與卸載競(jìng)態(tài)開發(fā)環(huán)境下若 200ms 內(nèi)更新過于頻繁會(huì)輸出性能告警并打印本次更新的 props方便排查不必要的重渲染。加載狀態(tài)內(nèi)部 loading 標(biāo)志初始為true在應(yīng)用的mountPromise落定后無論成功還是失敗清除。這一行為與autoSetLoading無關(guān)——該標(biāo)志只用于選擇內(nèi)置指示器若以它為條件才清除 loading會(huì)讓自定義loader永遠(yuǎn)旋轉(zhuǎn)。不提供加載插槽時(shí)該狀態(tài)沒有任何可渲染的內(nèi)容。內(nèi)置 loaderMicroApp nameapp1 entryhttp://localhost:8000 autoSetLoading /內(nèi)置 loader 只是渲染字面量文本loading...的占位符見 MicroAppLoader.tsx。要獲得真正的 UI請(qǐng)傳入自己的loader。自定義 loaderMicroApp nameapp1 entryhttp://localhost:8000 loader{(loading) Spinner spinning{loading} /} /自定義loader獨(dú)立生效且優(yōu)先于內(nèi)置指示器因此配合它時(shí)autoSetLoading是多余的。wrapperClassName只在加載或錯(cuò)誤插槽激活時(shí)生效——因?yàn)橹挥心菚r(shí)組件才渲染帶定位的包裝元素。組件源碼MicroApp.tsx先選擇loader否則在autoSetLoading開啟時(shí)回退到內(nèi)置MicroAppLoader測(cè)試 MicroApp.test.tsx 專門驗(yàn)證了不設(shè)置autoSetLoading時(shí)自定義 loader 也會(huì)在掛載完成后結(jié)束這一行為。錯(cuò)誤處理默認(rèn)情況下來自加載load、bootstrap、mount 的錯(cuò)誤會(huì)從異步加載流程中重新拋出。請(qǐng)配置內(nèi)置或自定義錯(cuò)誤 UI以避免產(chǎn)生未處理的 promise rejection。??務(wù)必處理異步加載錯(cuò)誤既未設(shè)置autoCaptureError也未設(shè)置errorBoundary時(shí)組件會(huì)重新拋出異步加載錯(cuò)誤。React 的 error boundary 無法捕獲 promise 回調(diào)中拋出的錯(cuò)誤所以必須配置組件自身的錯(cuò)誤 UI。組件源碼中的setComponentErrorMicroApp.tsx體現(xiàn)了這個(gè)設(shè)計(jì)只有配置了錯(cuò)誤邊界才把錯(cuò)誤寫入 state 渲染否則直接向外throw。mountMicroApp同時(shí)監(jiān)聽loadPromise、bootstrapPromise和mountPromise三個(gè) promise 的失敗shared/index.ts任一失敗都會(huì)觸發(fā)錯(cuò)誤 UI 并結(jié)束加載態(tài)。內(nèi)置錯(cuò)誤邊界MicroApp nameapp1 entryhttp://localhost:8000 autoCaptureError /內(nèi)置邊界渲染一個(gè)只包含error.message的裸div見 ErrorBoundary.tsx。生產(chǎn)環(huán)境請(qǐng)傳入自己的errorBoundary。自定義錯(cuò)誤邊界MicroApp nameapp1 entryhttp://localhost:8000 errorBoundary{(error) ErrorPanel message{error.message} /} /加載與錯(cuò)誤同時(shí)配置MicroApp nameapp1 entryhttp://localhost:8000 autoSetLoading autoCaptureError /測(cè)試 MicroApp.test.tsx 驗(yàn)證了加載失敗時(shí)errorBoundary插槽能正確渲染錯(cuò)誤消息、同時(shí)加載插槽被清除的行為。更系統(tǒng)的錯(cuò)誤處理方案參見處理加載與運(yùn)行時(shí)錯(cuò)誤與addErrorHandler/removeErrorHandler。通過 ref 獲取運(yùn)行實(shí)例組件是一個(gè)forwardRef。轉(zhuǎn)發(fā)的 ref 指向運(yùn)行中的微應(yīng)用句柄——來自qiankunjs/single-spa的 Parcel即qiankun中的MicroApp類型由qiankunjs/react以MicroAppType重新導(dǎo)出因此你可以讀取它的狀態(tài)、等待它的生命周期 promiseimport { useRef } from react; import { MicroApp } from qiankunjs/react; import { type MicroAppType } from qiankunjs/react; function Page() { const microAppRef useRefMicroAppType(undefined); const logStatus () { console.log(microAppRef.current?.getStatus()); }; return ( button typebutton onClick{logStatus}Check status/button MicroApp nameapp1 entryhttp://localhost:8000 autoSetLoading ref{microAppRef} / / ); }MicroAppType在共享層還擴(kuò)展了_unmounting、_updatingPromise、_updatingTimestamp三個(gè)內(nèi)部字段shared/index.ts它們是組件協(xié)調(diào)更新與卸載競(jìng)態(tài)更新串行化的私有狀態(tài)。ref 句柄成員句柄是 single-spa 的 Parcel 接口成員類型說明getStatus()() Status當(dāng)前生命周期狀態(tài)見下。mount()() Promisenull掛載應(yīng)用。unmount()() Promisenull卸載應(yīng)用。update?(props)(props) Promiseunknown推送新 props僅當(dāng)應(yīng)用導(dǎo)出了update生命周期時(shí)存在。loadPromisePromisenull源碼加載完成時(shí) resolve。bootstrapPromisePromisenull應(yīng)用完成 bootstrap 時(shí) resolve。mountPromisePromisenull應(yīng)用完成掛載時(shí) resolve。unmountPromisePromisenull應(yīng)用完成卸載時(shí) resolve。getStatus()返回的狀態(tài)之一NOT_LOADED、LOADING_SOURCE_CODE、NOT_BOOTSTRAPPED、BOOTSTRAPPING、NOT_MOUNTED、MOUNTING、MOUNTED、UPDATING、UNMOUNTING、UNLOADING、SKIP_BECAUSE_BROKEN、LOAD_ERROR。??讓組件管理生命周期ref 用于讀取狀態(tài)和等待 promise不要自己調(diào)用它的mount()/unmount()——組件掌管掛載 / 更新 / 卸載并防護(hù)并發(fā)卸載與重掛載。手動(dòng)調(diào)用這些方法容易破壞內(nèi)部狀態(tài)。傳遞配置settings加載器與沙箱相關(guān)的選項(xiàng)都通過settings一個(gè)AppConfiguration傳入MicroApp nameapp1 entryhttp://localhost:8000 settings{{ sandbox: { styleIsolation: true } }} /settings會(huì)被原樣交給loadMicroAppshared/index.ts 中與lifeCycles一起作為第二、第三個(gè)參數(shù)傳入——組件不會(huì)替你設(shè)置任何默認(rèn)值。注意loadMicroApp的container必須是真實(shí) DOM 元素而非選擇器字符串這一點(diǎn)由組件內(nèi)部的容器div保證測(cè)試 MicroApp.test.tsx 斷言了組件把自己創(chuàng)建的容器交給了 qiankun。sandbox.styleIsolation實(shí)際啟用了什么參見樣式隔離sandbox本身的含義參見 JS 沙箱。生命周期鉤子lifeCycles宿主側(cè)生命周期鉤子通過lifeCycles傳入只作用于該組件創(chuàng)建的實(shí)例。每個(gè)鉤子可以是單個(gè)函數(shù)或函數(shù)數(shù)組MicroApp nameapp1 entryhttp://localhost:8000 lifeCycles{{ beforeMount: async (app) console.log(before mount, app.name), afterMount: async (app) console.log(mounted, app.name), }} /完整的鉤子列表與簽名參見生命周期鉤子。實(shí)現(xiàn)上mountMicroApp把lifeCycles原樣傳給loadMicroApp的第三個(gè)參數(shù)由 qiankun 在其自身 addons 之上合并——源碼注釋特別記錄了一個(gè)歷史教訓(xùn)曾用concat(undefined, hook)包裝鉤子導(dǎo)致產(chǎn)生[undefined, hook]數(shù)組qiankun 會(huì)把它當(dāng)作鉤子調(diào)用導(dǎo)致所有傳入lifeCycles的應(yīng)用掛載即崩潰因此現(xiàn)在保持原樣傳遞shared/index.ts。樣式鉤子組件始終會(huì)附加兩個(gè)可供 CSS 定位的類元素類名包裝元素僅在加載器或錯(cuò)誤邊界激活時(shí)渲染qiankun-micro-app-wrapper掛載容器始終渲染qiankun-micro-app-container.qiankun-micro-app-wrapper { position: relative; /* 內(nèi)聯(lián)樣式已設(shè)置可在此補(bǔ)充布局 */ } .qiankun-micro-app-container { min-height: 240px; }wrapperClassName和className會(huì)被前置拼接到這兩個(gè)類之前見 MicroApp.tsx因此你的類與 qiankun 的鉤子類會(huì)同時(shí)出現(xiàn)在元素上。容器排序的一個(gè)隱藏細(xì)節(jié)組件刻意把掛載容器放在包裝元素的第一個(gè)子節(jié)點(diǎn)位置MicroApp.tsx。原因是qiankun 以容器的 XPath 為鍵做 parcel 緩存與同容器串行化而 XPath 計(jì)數(shù)的是同標(biāo)簽兄弟節(jié)點(diǎn)之前的元素。若 loader / error 面板條件渲染在容器之前會(huì)在兩次掛載之間改變?cè)撔蛱?hào)把同一個(gè)應(yīng)用靜默拆成兩個(gè)緩存條目。插槽渲染在容器之后還能在不依賴 z-index 的情況下蓋在應(yīng)用內(nèi)容之上。這一約束被測(cè)試 MicroApp.test.tsx 明確守護(hù)。底層工作原理掛載以name為鍵更改name會(huì)完整重掛載一個(gè)全新應(yīng)用。組件通過useEffect依賴[name]實(shí)現(xiàn)MicroApp.tsx且掛載/卸載經(jīng)由一條lifecycleRefpromise 鏈串行化——effect 的 cleanup 可能落在掛載仍在飛行中時(shí)React StrictMode 在開發(fā)模式下每次掛載都會(huì)如此卸載必須先等待那次掛載完成否則會(huì)找不到實(shí)例而跳過卸載導(dǎo)致實(shí)例一直掛載著、后繼實(shí)例永遠(yuǎn)等它。測(cè)試 MicroApp.test.tsx 分別驗(yàn)證了 StrictMode 下只留下一個(gè)存活實(shí)例、快速切換name時(shí)事件嚴(yán)格按mount:a → unmount:a → mount:b → …串行執(zhí)行。props 更新由深比較驅(qū)動(dòng)轉(zhuǎn)發(fā) props 經(jīng)useDeepComparelodashisEqual比較后變化時(shí)走microApp.update且更新鏈與掛載 promise 對(duì)齊不會(huì)在掛載完成前誤發(fā)更新。卸載時(shí)標(biāo)記防競(jìng)態(tài)實(shí)例狀態(tài)為MOUNTED時(shí)組件在拆卸前先把microApp._unmounting true使 prop 更新不會(huì)與卸載競(jìng)爭(zhēng)MicroApp.tsx。組件卸載時(shí)unmountMicroApp先等待mountPromise再調(diào)用unmount()shared/index.ts。相關(guān)資源loadMicroApp—— 本組件封裝的底層命令式 API。AppConfiguration——settings的數(shù)據(jù)結(jié)構(gòu)。生命周期鉤子 ——lifeCycles的數(shù)據(jù)結(jié)構(gòu)。Vue 版MicroApp組件 —— Vue 版本注意Vue 通過專門的appProps對(duì)象傳遞應(yīng)用 props。同時(shí)運(yùn)行多個(gè)微應(yīng)用實(shí)例組件源碼MicroApp.tsx、MicroAppLink.tsx、共享邏輯 shared/index.ts 與 shared/link.ts。贊分享前端微前端【免費(fèi)下載鏈接】qiankun Blazing fast, simple and complete solution for micro frontends.項(xiàng)目地址https://gitcode.com/gh_mirrors/qi/qiankun點(diǎn)擊查看免費(fèi)下載相關(guān)推薦EngineerCMS工程師的知識(shí)管理利器EngineerCMS工程師的知識(shí)管理利器 在數(shù)字化時(shí)代工程師們面臨著海量信息的挑戰(zhàn)如何高效地管理、共享和利用這些知識(shí)成為了迫切的需求。今天我們要介紹的前端微前端qiankun Vue 綁定實(shí)戰(zhàn)指南用 qiankunjs/vue 的 MicroApp 組件聲明式加載微應(yīng)用qiankun Vue 綁定實(shí)戰(zhàn)指南用 qiankunjs/vue 的 MicroApp 組件聲明式加載微應(yīng)用 qiankunjs/vue 是 qiank前端微前端貓抓資源嗅探插件實(shí)戰(zhàn)指南從捕獲到M3U8合并的完整流程貓抓資源嗅探插件實(shí)戰(zhàn)指南從捕獲到M3U8合并的完整流程 貓抓 cat catch 是一款開源的瀏覽器資源嗅探擴(kuò)展它實(shí)時(shí)監(jiān)聽網(wǎng)頁發(fā)出的網(wǎng)絡(luò)請(qǐng)求把藏在頁面里的前端微前端上一篇深入解析RAPIDS cuDF中的cudf.pandas加速機(jī)制下一篇Semi Design 暗色模式深度解析與實(shí)踐指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考