實現微前端的十種方式 【二】
- 實現微前端,我想了一想,大概有十種方式
- 想學習微前端的小夥伴,能夠看我以前對微前端源碼解析、加載方式、以及我開源的微前端框架chunchao源碼
- 簡單的文章,通俗易懂,感受不錯記得點個
在看
和關注
哦
目前主流的微前端實現方式(基座加載式)
- 以基座爲入口,配置不一樣的子應用入口地址,達到實現微前端的效果
- 目前微前端開源的框架:
chunchao
、qiankun
,其中chunchao
僅僅200行代碼就實現了,是一個很是值得定製開發的微前端雛形框架
- 微前端基座模式配置
如何實現基座模式加載子應用?
- 劫持前端路由,重寫
hashchange
和popstate
事件
const HIJACK_EVENTS_NAME = /^(hashchange|popstate)$/i;
const EVENTS_POOL = {
hashchange: [],
popstate: [],
};
window.addEventListener('hashchange', loadApps);
window.addEventListener('popstate', loadApps);
const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;
window.addEventListener = function (eventName, handler) {
if (
eventName &&
HIJACK_EVENTS_NAME.test(eventName) &&
typeof handler === 'function'
) {
EVENTS_POOL[eventName].indexOf(handler) === -1 &&
EVENTS_POOL[eventName].push(handler);
}
return originalAddEventListener.apply(this, arguments);
};
- 根據不一樣的入口,去拉取子應用的
js
、css
等資源
/**
*
* @param {string} entry
* @param {string} function
*/
const Apps = [] //子應用隊列
function registryApp(entry,activeRule) {
Apps.push({
entry,
activeRule
})
}
- 註冊完了以後,就要找到須要加載的app,而且拉取資源
export async function loadApp() {
const shouldMountApp = Apps.filter(shouldBeActive);
const App = shouldMountApp.pop();
fetch(App.entry)
.then(function (response) {
return response.text();
})
.then(async function (text) {
const dom = document.createElement('div');
dom.innerHTML = text;
const entryPath = App.entry;
const scripts = dom.querySelectorAll('script');
const subapp = document.querySelector('#subApp-content');
const paromiseArr =
scripts &&
Array.from(scripts).map((item) => {
if (item.src) {
const url = window.location.protocol + '//' + window.location.host;
return fetch(`${entryPath}/${item.src}`.replace(url, '')).then(
function (response) {
return response.text();
}
);
} else {
return Promise.resolve(item.textContent);
}
});
subapp.appendChild(dom);
const res = await Promise.all(paromiseArr);
if (res && res.length > 0) {
res.forEach((item) => {
const script = document.createElement('script');
script.innerText = item;
subapp.appendChild(script);
});
}
});
}
- shouldBeActive根據傳入的規則去判斷是否須要此時掛載:
export function shouldBeActive(app){
return app.activeRule(window.location)
}
export async function handleScripts(entryPath,subapp,dom) {
const scripts = dom.querySelectorAll('script');
const paromiseArr =
scripts &&
Array.from(scripts).map((item) => {
if (item.src) {
const url = window.location.protocol + '//' + window.location.host;
return fetch(`${entryPath}/${item.src}`.replace(url, '')).then(
function (response) {
return response.text();
}
);
} else {
return Promise.resolve(item.textContent);
}
});
const res = await Promise.all(paromiseArr);
if (res && res.length > 0) {
res.forEach((item) => {
const script = document.createElement('script');
script.innerText = item;
subapp.appendChild(script);
});
}
}
export async function handleStyles(entryPath, subapp, dom) {
const arr = [];
const styles = dom.querySelectorAll('style');
const links = Array.from(dom.querySelectorAll('link')).filter(
(item) => item.rel === 'stylesheet'
);
const realArr = arr.concat(styles,links)
const paromiseArr =
arr &&
Array.from(realArr).map((item) => {
if (item.rel) {
const url = window.location.protocol + '//' + window.location.host;
return fetch(`${entryPath}/${item.href}`.replace(url, '')).then(
function (response) {
return response.text();
}
);
} else {
return Promise.resolve(item.textContent);
}
});
const res = await Promise.all(paromiseArr);
if (res && res.length > 0) {
res.forEach((item) => {
const style = document.createElement('style');
style.innerHTML = item;
subapp.appendChild(style);
});
}
}
最後
- 認真收藏這個系列吧,記得點個關注和在看,相信你能收穫不少不少~
- 我是
Peter
,架構設計過桌面跨平臺IM
軟件、重型Saas平臺以及手機端跨平臺APP
,個人微信:CALASFxiaotan
- 另外歡迎收藏個人資料網站:前端生活社區:
https://qianduan.life
,感受對你有幫助,能夠右下角點個在看
,關注
一波公衆號:[前端巔峯
]