实现微前端的十种方式 【二】
- 实现微前端,我想了一想,大概有十种方式
- 想学习微前端的小伙伴,可以看我之前对微前端源码解析、加载方式、以及我开源的微前端框架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);};
/** * * @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
,感觉对你有帮助,可以右下角点个在看
,关注
一波公众号:[前端巅峰
]