文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

微前端框架导入加载子应用的方法是什么

2024-04-02 19:55

关注

本篇内容主要讲解“微前端框架导入加载子应用的方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“微前端框架导入加载子应用的方法是什么”吧!

下面代码,我指定的entry,就是子应用的访问入口地址

微前端框架导入加载子应用的方法是什么

微前端到底是怎么回事呢?  我画了一张图

微前端框架导入加载子应用的方法是什么

我们今天不谈其他的实现技术细节,坑点,就谈整体架构,这张图就能完全解释清楚

那么registerMicroApps,到底做了什么呢?

微前端框架导入加载子应用的方法是什么

源码解析下,只看重要部分今天:

lifeCycles是我们自己传入的生命周期函数(这里先不解释),跟react这种框架一样,微前端针对每个子应用,也封装了一些生命周期,如果你是小白,那我就用最简单的话告诉你,生命周期钩子,其实在框架源码就是一个函数编写调用顺序而已(有的分异步和同步)

apps就是我们传入的数组,子应用集合

代码里做了一些防重复注册、数据处理等

看源码,不要全部都看,那样很费时间,而且你也得不到利益最大化,只看最精髓、重要部分

无论上面做了上面子应用去重、数据处理,我只要盯着每个子应用,即app这个对象即可

看到了loadApp这个方法,我们可以大概猜测到,是通过这个方法加载

下面__rest是对数据进行处理

微前端框架导入加载子应用的方法是什么

loadApp这个函数有大概300行,挑最重点地方看

微前端框架导入加载子应用的方法是什么

registerApplication是single-spa的方法,我们这里通过loadApp这个方法,对数据进行处理

微前端框架导入加载子应用的方法是什么

上面这个函数,应该是整个微前端框架最复杂的地方,它最终会返回一个函数,当成函数传递给single-spa这个库的registerApplication方法使用

它的内部是switch case逻辑,然后返回一个数组

这是一个逻辑判断

case 0:            entry = app.entry, appappName = app.name;            _b = configuration.singular, singular = _b === void 0 ? false : _b, _c = configuration.sandbox, sandbox = _c === void 0 ? true : _c, importEntryOpts = __rest(configuration, ["singular", "sandbox"]);  return [4              , importEntry(entry, importEntryOpts)];

重点来了

会通过importEntry 去加载entry(子应用地址)

微前端框架导入加载子应用的方法是什么 

上面代码里最重要的,如果我们entry传入字符串,那么就会使用这个函数去加载HTML内容(其实微前端的所有子应用加载,都是把dom节点加载渲染到基座的index.html文件中的一个div标签内)

微前端框架导入加载子应用的方法是什么

importHTML这个函数,就是我们今晚最重要的一个点

传入url地址,发起fetch请求(此时由于域名或者端口不一样,会出现跨域,所有子应用的热更新开发模式下,webpack配置要做以下处理,部署也要考虑这个问题)

微前端框架导入加载子应用的方法是什么

整个importHTML函数好像很长很长,但是我们就看最重要的地方,一个框架(库),流程线很长+版本迭代原因,需要兼容老的版本,所以很多源码对于我们其实是无用的

微前端框架导入加载子应用的方法是什么

整个函数,最后返回了一个对象,这里很明显,通过fetch请求,获取了对应子应用entry入口的资源文件后,转换成了字符串

这里processTpl其实就是对这个子应用的dom模版(字符串格式)进行一个数据拼装,其实也不是很复杂,由于时间关系,可以自己看看过程,重点看结果

这里的思想,是redux的中间件源码思想,将数据进行了一层包装,高可用使用

function processTpl(tpl, baseURI) {  var scripts = [];  var styles = [];  var entry = null;  var template = tpl      .replace(HTML_COMMENT_REGEX, '').replace(LINK_TAG_REGEX, function (match) {    var styleType = !!match.match(STYLE_TYPE_REGEX);  if (styleType) {  var styleHref = match.match(STYLE_HREF_REGEX);  var styleIgnore = match.match(LINK_IGNORE_REGEX);  if (styleHref) {  var href = styleHref && styleHref[2];  var newHref = href;  if (href && !hasProtocol(href)) {            newHref = getEntirePath(href, baseURI);          }  if (styleIgnore) {  return genIgnoreAssetReplaceSymbol(newHref);          }          styles.push(newHref);  return genLinkReplaceSymbol(newHref);        }      }  var preloadOrPrefetchType = match.match(LINK_PRELOAD_OR_PREFETCH_REGEX) && match.match(LINK_HREF_REGEX);  if (preloadOrPrefetchType) {  var _match$matchmatch = match.match(LINK_HREF_REGEX),            _match$match3 = (0, _slicedToArray2["default"])(_match$match, 3),            linkHref = _match$match3[2];  return genLinkReplaceSymbol(linkHref, true);      }  return match;    }).replace(STYLE_TAG_REGEX, function (match) {  if (STYLE_IGNORE_REGEX.test(match)) {  return genIgnoreAssetReplaceSymbol('style file');      }  return match;    }).replace(ALL_SCRIPT_REGEX, function (match) {  var scriptIgnore = match.match(SCRIPT_IGNORE_REGEX); // in order to keep the exec order of all javascripts  // if it is a external script  if (SCRIPT_TAG_REGEX.test(match) && match.match(SCRIPT_SRC_REGEX)) {    var matchmatchedScriptEntry = match.match(SCRIPT_ENTRY_REGEX);  var matchmatchedScriptSrcMatch = match.match(SCRIPT_SRC_REGEX);  var matchedScriptSrc = matchedScriptSrcMatch && matchedScriptSrcMatch[2];  if (entry && matchedScriptEntry) {  throw new SyntaxError('You should not set multiply entry script!');        } else {  // append the domain while the script not have an protocol prefix  if (matchedScriptSrc && !hasProtocol(matchedScriptSrc)) {            matchedScriptSrc = getEntirePath(matchedScriptSrc, baseURI);          }          entryentry = entry || matchedScriptEntry && matchedScriptSrc;        }  if (scriptIgnore) {  return genIgnoreAssetReplaceSymbol(matchedScriptSrc || 'js file');        }  if (matchedScriptSrc) {  var asyncScript = !!match.match(SCRIPT_ASYNC_REGEX);          scripts.push(asyncScript ? {            async: true,            src: matchedScriptSrc          } : matchedScriptSrc);  return genScriptReplaceSymbol(matchedScriptSrc, asyncScript);        }  return match;      } else {  if (scriptIgnore) {  return genIgnoreAssetReplaceSymbol('js file');        } // if it is an inline script  var code = (0, _utils.getInlineCode)(match); // remove script blocks when all of these lines are comments.  var isPureCommentBlock = code.split(/[\r\n]+/).every(function (line) {  return !line.trim() || line.trim().startsWith('//');        });  if (!isPureCommentBlock) {          scripts.push(match);        }  return inlineScriptReplaceSymbol;      }    });    scriptsscripts = scripts.filter(function (script) {  // filter empty script  return !!script;    });  return {      template: template,      scripts: scripts,      styles: styles,  // set the last script as entry if have not set      entry: entry || scripts[scripts.length - 1]    };  }

最终返回了一个对象,此时已经不是一个纯html的字符串了,而是一个对象,而且脚本样式都分离了

微前端框架导入加载子应用的方法是什么

这个是框架帮我们处理的,必须要设置一个入口js文件

// set the last script as entry if have not set

下面是真正的single-spa源码,注册子应用,用apps这个数组去收集所有的子应用(数组每一项已经拥有了脚本、html、css样式的内容)

微前端框架导入加载子应用的方法是什么

此时我们只要根据我们之前编写的activeRule和监听前端路由变化去控制展示子应用即可,原理如下:(今天不做过多讲解这块)

window.addEventListener('hashchange', reroute);  window.addEventListener('popstate', reroute);  // 拦截所有注册的事件,以便确保这里的事件总是第一个执行  const originalAddEventListener = window.addEventListener;  const originalRemoveEventListener = window.removeEventListener;  window.addEventListener = function (eventName, handler, args) {      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);  };  window.removeEventListener = function (eventName, handler) {      if (eventName && HIJACK_EVENTS_NAME.test(eventName) && typeof handler === 'function') {          let eventList = EVENTS_POOL[eventName];          eventList.indexOf(handler) > -1 && (EVENTS_POOL[eventName] = eventList.filter(fn => fn !== handler));      }      return originalRemoveEventListener.apply(this, arguments);  };

也是redux的中间件思想,劫持了事件,然后进行派发,优先调用微前端框架的路由事件,然后进行过滤展示子应用:

export function getAppsToLoad() {      return APPS.filter(notSkipped).filter(withoutLoadError).filter(isntLoaded).filter(shouldBeActive);  }

整个微前端的触发流程

微前端框架导入加载子应用的方法是什么

到此,相信大家对“微前端框架导入加载子应用的方法是什么”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯