正文
经过我们团队的调研,我们选择了无界作为微前端的技术栈。目前的使用效果非常好,不仅性能表现出色,而且使用体验也不错。
尽管在使用的过程中,我们也遇到了一些问题,但这些问题往往源于我们对框架实现的不熟悉。我们深入研究了无界技术的源码,并将在本文中与大家分享。本文将重点探讨无界微前端如何渲染子应用的。
无界渲染子应用的步骤
无界与其他微前端框架(例如qiankun)的主要区别在于其独特的 JS 沙箱机制。无界使用 iframe 来实现 JS 沙箱,由于这个设计,无界在以下方面表现得更加出色:
- 应用切换没有清理成本
- 允许一个页面同时激活多个子应用
- 性能相对更优
无界渲染子应用,主要分为以下几个步骤:
- 创建子应用 iframe
- 解析入口 HTML
- 创建 webComponent,并挂载 HTML
- 运行 JS 渲染 UI
创建子应用 iframe
要在 iframe 中运行 JS,首先得有一个 iframe。
export function iframeGenerator( sandbox: WuJie, attrs: { [key: string]: any }, mainHostPath: string, appHostPath: string, appRoutePath: string ): HTMLIFrameElement { // 创建 iframe 的 DOM const iframe = window.document.createElement("iframe"); // 设置 iframe 的 attr setAttrsToElement(iframe, { // iframe 的 url 设置为主应用的域名 src: mainHostPath, style: "display: none", ...attrs, name: sandbox.id, [WUJIE_DATA_FLAG]: "" }); // 将 iframe 插入到 document 中 window.document.body.appendChild(iframe); const iframeWindow = iframe.contentWindow; // 停止 iframe 的加载 sandbox.iframeReady = stopIframeLoading(iframeWindow).then(() => { // 省略其他内容 } // 注入无界的变量到 iframeWindow,例如 __WUJIE patchIframeVariable(iframeWindow, sandbox, appHostPath); // 省略其他内容 return iframe; }
创建 iframe 主要有以下流程:
- 创建 iframe 的 DOM,并设置属性
- 将 iframe 插入到 document 中(此时 iframe 会立即访问 src)
- 停止 iframe 的加载(stopIframeLoading)
为什么要停止 iframe 的加载?
因为要创建一个纯净的 iframe,防止 iframe 被污染,假如该 url 的 JS 代码,声明了一些全局变量、函数,就可能影响到子应用的运行(假如子应用也有同名的变量、函数)
为什么 iframe 的 src 要设置为主应用的域名
为了实现应用间(iframe 间)通讯,无界子应用 iframe 的 url 会设置为主应用的域名(同域)
- 主应用域名为
a.com
- 子应用域名为
b.com
,但它对应的 iframe 域名为a.com
,所以要设置b.com
的资源能够允许跨域访问
因此 iframe 的 location.href
并不是子应用的 url。
解析入口 HTML
iframe 中运行 js,首先要知道要运行哪些 js
我们可以通过解析入口 HTML 来确定需要运行的 JS 内容
假设有以下HTML
经过 importHTML
处理后,结果如下:
- template 模板部分,去掉了所有的 script 和 style