常见微前端方案

转载请注明出处,点击此处 查看更多精彩内容。

iframe

iframe 是 HTML 的内联框架元素,表示嵌套的 Browsing Context,它能够将另一个 HTML 页面嵌入到当前页面中,每个嵌入的 Browsing Context 都有自己的会话历史记录和 DOM 树。

每个浏览上下文都拥有完整的文档环境,因此页面上每个 iframe 都需要增加内存和其它计算资源,虽然理论上来说能够在代码中写出来无限多的 iframe,但是这么做可能会导致某些性能问题。

优点

  • Web 应用隔离的非常完美,无论是 JavaScript、CSS、DOM 都完全隔离开来。
  • 非常简单,使用没有任何心智负担。

缺点

  • DOM 结构不共享,弹窗只能在 iframe 内部展示,无法覆盖全局。
  • 路由状态丢失,刷新页面会导致 iframe 的 url 状态丢失、后退前进按钮无法使用。
  • 性能差,每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。
  • 应用之间通信困难,全局上下文完全隔离,内存变量不共享,无法访问非同源的 window 对象的几乎所有属性,跨域通信仅可通过 window.postMessage() 来实现。

路由转发

路由分发式微前端,即通过路由将不同的业务分发到不同的独立前端应用上。最常用的方案是通过 HTTP 服务的反向代理(如 Nginx)将不同页面的请求分发到不同的服务上。

优点

  • 实现简单。
  • 维护、开发成本低。
  • 不需要对现有应用进行改造。

缺点

  • 用户体验不好,每次切换应用时,浏览器都需要重新加载页面。
  • 子应用之间的通信比较困难。
  • 多个子应用无法并存。
  • 子应用切换时需要重新登录。

动态加载模块

创建一个基座应用,允许子应用单独部署。为了实现这一点,创建一个 manifest 文件,记录上线的子应用及版本信息,当子应用部署更新时修改 manifest 文件,基座应用通过 manifest 检查更新子应用资源。

改变每个子应用加载的 JavaScript 文件有很多的方法:

  • Web 服务器:在你的 Web 服务器为每个子应用的正确版本创建一个动态脚本。
  • 使用模块加载 例如 SystemJS 可以在浏览器通过动态 urls 下载并执行 JavaScript 代码。

npm

每个子应用在一个单独的代码仓库中,每次更新时发布一个新版本到 npm,创建一个基座应用,通过 npm 安装每个子应用。

优点

  • npm 安装对于开发中更熟悉,易于搭建。

缺点

  • 子应用发生变更时,基座应用需要重新安装、重新构建和重新部署。
  • 无法动态安装、卸载子应用。

Web Component

Web Component 是一套不同的技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 Web 应用中使用它们。

Web Components 由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。

  • Custom Element(自定义元素)

    一组 JavaScript API,允许您定义 Custom Elements 及其行为,然后可以在您的用户界面中按照需要使用它们。
  • Shadow DOM(影子 DOM)

    一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
  • HTML Template(HTML 模板)

    <template><slot> 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。

基于 Web ComponentShadow Dom 能力,我们也可以实现微前端,将多个子应用聚合起来。

const shadow = document.querySelector('#hostElement').attachShadow({mode: 'open'});
// url 为应用的地址,基于 fetch,我们可以获取到应用的 html 模板,添加到指定节点下
fetch(url).then(res => {
    shadow.innerHTML = res
});

优点

  • 实现简单。
  • 完全技术栈无关。
  • 不需要对现有应用进行改造。
  • CSS 和 JavaScript 天然隔离,互不干扰。

缺点

  • 没有统一的 Web Component 规范。
  • 浏览器实现不一致。
  • Web 组件存在向后不兼容的版本问题。
  • 开发成本较高。

EMP

EMP 基于 Webpack5 的 Module Federation 实现,用一个词概括,就是“去中心化”,在 EMP 的方案中不需要中心化的基座,每一个微前端应用都可以通过远程调用的方式引入共享模块。

优点

  • Webpack5 Module Federation 可以保证所有子应用依赖解耦。
  • 模块远程 TypeScript 支持。
  • 应用间去中心化的调用、共享模块。

缺点

  • 对 Webpack 强依赖,老旧项目不友好。
  • 没有有效的 CSS 沙箱和 JavaScript 沙箱,需要靠用户自觉。
  • 主、子应用的路由可能发生冲突。
  • 子应用保活、多应用激活无法实现。

single-spa / qiankun

single-spa 是一个目前主流的微前端技术方案。

single-spa 从现代框架组件生命周期中获得灵感,将生命周期应用于整个应用程序,其主要实现思路:

  • 预先注册子应用(激活路由、子应用资源、生命周期函数)。
  • 监听路由的变化,匹配到了激活的路由则加载子应用资源,顺序调用生命周期函数并最终渲染到容器。

single-spa 未解决子应用加载、应用隔离、子应用通信等问题。

qiankun 微前端架构则进一步对 single-spa 方案进行完善,主要的完善点:

  • 子应用资源由 JavaScript 列表修改进为一个 url,大大减轻注册子应用的复杂度。
  • 增加资源预加载能力,预先缓存子应用的 HTML、JavaScript、CSS 资源,加快子应用的打开速度。
  • 实现应用隔离,完成 JavaScript 隔离方案 (window 工厂) 和 CSS 隔离方案 (类 Vue 的 scoped)。
  • 提供了 @umijs/plugin-qiankunumi 应用一键切换成微前端架构系统。

优点

  • 监听路由自动的加载、卸载当前路由对应的子应用。
  • 路由保持,浏览器刷新、前进、后退,都可以作用到子应用。
  • 应用间通信简单,全局注入。
  • 完备的沙箱方案,JavaScript 沙箱做了 SnapshotSandboxLegacySandboxProxySandbox 三套渐进增强方案,CSS 沙箱做了两套 strictStyleIsolationexperimentalStyleIsolation 两套适用不同场景的方案。

缺点

  • 改造成本较大,从 Webpack、代码、路由等等都要做一系列的适配。
  • 基于路由匹配,无法同时激活多个子应用,也不支持子应用保活。
  • CSS 沙箱无法绝对的隔离,JavaScript 沙箱在某些场景下执行性能下降严重。
  • 无法支持 Vite 等 ESM 脚本运行。

无界(wujie)

无界利用 iframe 的沙箱机制,将子应用的 JavaScript 注入到基座应用同域的 iframe 中运行,并采用 Web Component 实现页面的样式隔离。

  • 应用加载机制和 JavaScript 沙箱机制

    将子应用的 JavaScript 注入主应用同域的 iframe 中运行,iframe 是一个原生的 window 沙箱,内部有完整的 historylocation 接口,子应用实例运行在 iframe 中,路由主应用解耦,可以直接在业务组件里面启动应用。
  • 路由同步机制

    劫持 iframehistory.pushStatehistory.replaceState,就可以将子应用的 url 同步到主应用的 query 参数上,当刷新浏览器初始化 iframe 时,读回子应用的 url 并使用 iframehistory.replaceState 进行同步。
  • iframe 连接机制和 CSS 沙箱机制

    无界采用 Web Component 来实现页面的样式隔离,无界会创建一个 wujie 自定义元素,然后将子应用的完整结构渲染在内部。子应用的实例在 iframe 内运行,DOM 在主应用容器下的 Web Component 内,通过代理 iframedocumentWeb Component,可以实现两者的互联。
  • 通信机制

    承载子应用的 iframe 和主应用是同域的,所以主、子应用天然就可以很好的进行通信,无界提供三种通信方式。
    • props 注入机制,子应用通过 $wujie.props 可以轻松拿到主应用注入的数据。
    • 子应用 iframe 沙箱和主应用同源,子应用可以直接通过 window.parent 和主应用通信。
    • 无界提供了 EventBus 实例,注入到主应用和子应用,所有的应用可以去中心化的进行通信。

优点

  • 多应用同时激活在线

    框架具备同时激活多应用,并保持这些应用路由同步的能力。
  • 组件式的使用方式

    无需注册,更无需路由适配,在组件内使用,跟随组件装载、卸载。
  • 应用级别的 keep-alive

    子应用开启保活模式后,应用发生切换时整个子应用的状态可以保存下来不丢失,结合预执行模式可以获得类似 SSR 的打开体验。
  • 纯净无污染
    • 无界利用 iframeWeb Component 来搭建天然的 JavaScript 隔离沙箱和 CSS 隔离沙箱。
    • 利用 iframehistory 和主应用的 history 在同一个 top-level Browsing Context 来搭建天然的路由同步机制。
    • 副作用局限在沙箱内部,子应用切换无需任何清理工作,没有额外的切换成本。
  • 性能和体积兼具
    • 子应用执行性能和原生一致,子应用实例运行在 iframewindow 上下文中,避免 with(proxyWindow){code} 这样指定代码执行上下文导致的性能下降,但是多了实例化 iframe 的一次性的开销,可以通过 preload 提前实例化。
    • 体积比较轻量,借助 iframeWeb Component 来实现沙箱,有效的减小了代码量。
  • 开箱即用

    不管是样式的兼容、路由的处理、弹窗的处理、热更新的加载,子应用完成接入即可开箱即用无需额外处理,应用接入成本也极低。
  • 子应用运行在 iframe 中,原生支持 ESM 的脚本。

缺点

  • iframe 的一些坑尚未解决,如路由回退问题。

micro-app

micro-app 借鉴了 Web Component 的思想,通过 Custom Element 结合自定义的 Shadow Dom,将微前端封装成一个类 Web Component 组件,从而实现微前端的组件化渲染。并且由于自定义 Shadow Dom 的隔离特性,micro-app 不需要像 single-spaqiankun 一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改 Webpack 配置,在基座应用中嵌入一行代码即可渲染一个微前端应用,是目前市面上接入微前端成本最低的方案。

优点

  • 零依赖

    micro-app 没有任何依赖,这赋予它小巧的体积和更高的扩展性。
  • 使用简单

    我们将所有功能都封装到一个类 Web Component 组件中,从而实现在基座应用中嵌入一行代码即可渲染一个微前端应用。同时 micro-app 还提供了 JavaScript 沙箱、样式隔离、元素隔离、预加载、数据通信、静态资源补全等一系列完善的功能。
  • 兼容所有框架

    为了保证各个业务之间独立开发、独立部署的能力,micro-app 做了诸多兼容,在任何技术框架中都可以正常运行。

缺点

  • 多应用激活后无法保持子应用的路由状态,刷新后全部丢失。
  • 对于不支持Web Component 的浏览器没有做降级处理。
  • 支持 Vite 运行,但必须使用 plugin 改造子应用,且 JavaScript 代码没办法做沙箱隔离。
  • 较长时间未更新,稳定版最近一次发版(v0.8.10)时间是 2022.08.19,测试版最近一次发版(v1.0.0-alpha.10)时间是 2022.10.11。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容