chunchao
源码开源,仅仅为了让你们学习微前端的工做模式而已,实际项目中,咱们有使用Paas模式,web components,git submodule等模式均可以实现微前端,固然业内确定有独特的、优于这些模式的微前端实现export async function loadApp() { const shouldMountApp = Apps.filter(shouldBeActive); console.log(shouldMountApp, 'shouldMountApp'); fetch(shouldMountApp[0].entry) .then(function (response) { return response.text(); }) .then(function (text) { const dom = document.createElement('div'); dom.innerHTML = text; const subapp = document.querySelector('#subApp-content'); subapp && subapp.appendChild(dom); }); }
dom
节点,渲染到基座的对应子应用节点中script
、style
标签❝样式隔离、沙箱隔离并非难题,这里不着重实现,能够参考shadow dom,qiankun的proxy隔离代理window实现html
❞前端
fetch
去加载·
script、style`标签,而后用key-value形式缓存在一个对象中(方便缓存第二次直接获取),他们的fetch还能够用闭包传入或者使用默认的fetch,这里不作过多源码解析`<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>subapp1</title> </head> <body> <div>subapp1</div> </body> <script src="/index.js"></script> <script> alert('subapp1') </script> </html>
script
标签,须要加载,根据加载方式,分为html内部的和经过script标签引入的<script src="/index.js"></script> <script> alert('subapp1') </script>
`export async function loadApp() { const shouldMountApp = Apps.filter(shouldBeActive); const App = shouldMountApp.pop(); }); `
script src="/index.js"
,可是读取script标签的src属性,会自动+上主应用的前缀,因此要考虑下如何处理const url = window.location.protocol+"//"+window.location.host `
const res = await Promise.all(paromiseArr); console.log(res, 'res'); if (res && res.length > 0) { res.forEach((item) => { const script = document.createElement('script'); script.innerText = item; subapp.appendChild(script); }); }
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); }); } }); }
`subapp.appendChild(dom); handleScripts(entryPath,subapp,dom);`
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 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 subapp = document.querySelector('#subApp-content'); subapp.appendChild(dom); handleScripts(entryPath, subapp, dom); }); } `
`<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>subapp1</title> <style> body { color: red; } </style> </head> <body> <div>subapp1</div> </body> <script src="/index.js"></script> <script> alert('subapp1') </script> </html> `
handleScripts(entryPath, subapp, dom); handleStyles(entryPath, subapp, dom);
`` 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); }); } } ``
❝这里能够作个promise化,若是加载失败能够报个警告控制台,封装框架大都须要这个,不然没法debug.我这里作乞丐版,目前就不作那么正规了,设计框架原则你们不能忘记哈webpack
❞git
https://github.com/JinJieTan/chunchao
,记得给个star
哦若是你对性能优化有很深的研究,能够跟我一块儿交流交流,今天这里写得比较浅,可是大部分人都够用,以前问个人朋友,我让它写了一个定时器定时消费队列,最后也能用。哈哈github
另外欢迎收藏个人资料网站:前端生活社区:https://qianduan.life
,感受对你有帮助,能够右下角点个在看
,关注一波公众号:[前端巅峰
]web