介绍

MicroApp 是由京东前端团队推出的一款微前端框架,它从组件化的思维,基于类 WebComponent 进行微前端的渲染,旨在降低上手难度、提升工作效率。MicroApp 无关技术栈,也不和业务绑定,可以用于任何前端框架。

微前端是一种页面整合方案,它的核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,再将这些小型应用融合为一个完整的应用,或者将原本运行已久、没有关联的几个应用融合为一个应用。微前端既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性,相比一整块的前端仓库,微前端架构下的前端仓库倾向于更小更灵活。

升级亮点

距离 MicroApp 开源已经有一年多时间,在这段时间里我们收到了很多问题反馈,包括沙箱的性能、vite 的兼容、路由冲突等等,为了解决这些问题我们将很多核心功能进行升级和重构,经过不断的打磨和验证,最终推出 MicroApp1.0 正式版。

正式版的升级主要在以下几个方面:

  1. 更简洁的接入方式

  2. 沙箱的性能

  3. 虚拟路由系统

  4. 样式隔离

  5. 兼容 vite

  6. 开发工具

一行代码嵌入

MicroApp 借鉴了 WebComponent 的思想,通过 CustomElement 结合自定义的 ShadowDom,将微前端封装成一个类 WebComponent 组件,实现微前端的组件化渲染。在此基础上,通过实现 JS 隔离、样式隔离、路由隔离,降低子应用的接入成本,子应用只需设置允许跨域请求,不需要改动任何代码即可接入微前端,使用方式和 iframe 几乎一致,但却没有 iframe 存在的问题。

接入方式如下:

JS 沙箱的困境

在 MicroApp 开源后我们收到社区的一些反馈,其中一条关于性能的问题引起我们的重视。这不是 MicroApp 才存在的问题,而是微前端长久以来的难题,在社区有大量关于沙箱性能问题的讨论,却始终没有完美的解决方案。

MicroApp 采用的是和 qiankun 一样的 proxy+with 的沙箱方案,这也是目前 js 沙箱的主流方案 。with 沙箱的功能非常完善,但是性能损耗却非常明显,在社区中也不乏对 with 沙箱性能问题的讨论,但一直没有特别完美的解决方案,这是由于 with 改变了 js 的作用域链,从而产生大量的重复请求。问题的根源是 with,但又不全是 with 的问题,准确的说是 with 和 proxy 两者叠加造成的,with 和 proxy 本质上的性能都不高,需要一种方案避免对这两个方法的频繁读取操作,MicroApp 采用的解决方案是变量前置和异步防抖。

• 变量前置:是指使用 Object.defineProperty 定义全局变量,通过 get 和 set 设置响应数据,一是为了避免在 proxy 的 get 中进行多余的操作,二是 defineProperty 的性能比 proxy 更优秀 。

• 异步防抖:是指在子应用运行时对 promise 进行标记,确保在上一个 promise 执行完成之后才会进入下一个,避免并行触发,防止 promise 被频繁触发会造成性能损失。

在此基础上,MicroApp 沙箱还提供了快照、缓存、预加载等功能,在保证功能不变的前提下,彻底解决沙箱的性能问题,升级后的沙箱运行效率媲美原生 JS。

虚拟路由系统

微前端是将多个不同的 web 应用融合在一起渲染,但浏览器只有一个路由系统,这很容易造成应用之间的路由冲突,最常见的就是 vue3 的路由冲突问题。

上面是 vue-router 作者对于在微前端环境下的冲突问题的回答,他认为 vue-router 已经覆盖足够多场景,微前端的问题应该由微前端解决。

在我们刚开源时,并没有对路由进行隔离,用户对于 MicroApp 的问题几乎一半都和路由相关,因为一个路由系统同时满足多个应用的渲染容易导致冲突,也非常反直觉和难以理解,于是我们推出了虚拟路由系统。

概念图:

虚拟路由系统与浏览器的路由行为一致,它通过自定义 location 和 history 等核心路由 API,重写了 popState 和 hashChange 事件,拦截路由导航和事件,并提供了一系列自定义 API,模拟了在浏览器环境下的 Web 应用程序的渲染、跳转和返回等路由行为。子应用程序在这个虚拟路由系统中运行,与基座应用程序的路由相互隔离,从而避免相互影响,并增强了子应用程序与基座应用程序之间的交互能力。通过虚拟路由系统,基座应用程序可以方便地获取子应用程序的路由信息并控制子应用程序的跳转,子应用程序的路由信息会作为参数同步到浏览器地址上。此外,虚拟路由系统还提供了许多功能,帮助开发人员提高工作效率。

样式隔离方案升级

MicroApp 最初是基于 style 元素的 CSSStyleSheet 实现的样式隔离:即将 CSS 字符串插入 style 元素生成 CSSStyleSheet,遍历每个 CSS 规则,添加前缀实现样式隔离。

这种一种取巧的方式,利用浏览器自身的能力格式化 CSS,并在此基础上进行修改,省去很多工作量。但问题也出现在这里,不同浏览器对于相同的 CSS 生成的 CSSStyleSheet 可能会不同,这就导致我们在处理 CSSStyleSheet 会遇到不可以预知的问题,导致 CSS 表现不一致。

于是 MicroApp 换了一种方式来实现样式隔离,我们使用正则将 CSS 字符串切割成最小单元,每个单元包含一段 CSS 信息,将所有的信息整理生成 CSSTree,遍历 CSSTree 的每个规则,添加前缀实现样式隔离。

新的方案不但抹平了不同平台间的差异,在性能上相较于旧版普遍提升 30% 以上,并且拥有更加灵活的配置:

/* 对指定的选择器禁用样式隔离 *
/*! scopecss-disable .test1, .test2 */
.test1 {
  color: red;
}
.test2 {
  color: yellow;
}
.test3 {
  /* 在某一行中禁用样式隔离 */
  /*! scopecss-disable-next-line */
  background: url(/test.png);
}

vite 的兼容

在之前的版本中,MicroApp 也支持 vite 的接入,但必须关闭沙箱,因为 vite 打包出来的是 esm 类型的 js 文件,而 esm 无法运行在 with 环境中,但这样容易导致基座和子应用之间的冲突,显然是需要进一步优化的。

为此我们为 vite(更准确的说是为 esm 类型的项目)开发了一套 iframe 沙箱方案,将 esm 类型的 js 文件放入 iframe 中运行,并通过重写子应用底层原型链的方式,实现对 js 和元素的拦截和处理。

iframe 沙箱和 with 沙箱的实现方式不同,功能也略有不同,with 沙箱拥有更加灵活的操作,而 iframe 沙箱拥有更加严格的隔离环境,两者各有优劣。用户可以在两种沙箱之间灵活切换,以满足更多特殊场景的覆盖和兼容。

Micro-App-DevTools

Micro-App-DevTools 是基于 MicroApp 推出的一款 Chrome 浏览器插件,目的是为了在开发和使用 MicroApp 过程中提高效率。通过此插件可以有效的解决调试困难、模拟数据通信、查看视窗范围、设置路由、获取环境变量等诉求,进而更好地帮助用户去了解和使用 MicroApp。

方案详解

Micro-App-DevTools 通过模拟子应用开发环境,获取父应用数据,来可视化查看通讯数据,提高开发调试效率。对于路由,将会显示所有应用的路由,包含层层嵌套应用以及一个父应用多个子应用的路由,使不同团队应用也能快速定位自己问题,方便协作。还提供了全局变量和高亮视窗功能,实现快速定位范围,提高排查效率的功能,并集结了图标、右键、控制台的快捷进入方式,使用户快速上手,零成本使用。

总结

MicroApp 1.0 已经发布,我们将积极回应开发者的问题和反馈,并持续改进,以帮助更多开发者提高效率和改善开发体验。欢迎大家使用 MicroApp 并参与共建,也希望在 GitHub 上给我们点个 Star 来支持我们~

MicroApp Github 地址:

https://github.com/micro-zoe/micro-app

Micro-App-DevTools Github 地址:

https://github.com/micro-zoe/micro-app-chrome-plugin

MicroApp 官网地址:

https://micro-zoe.github.io/micro-app

作者:京东零售 马国华

来源:京东云开发者社区 转载请注明来源


↙↙↙阅读原文可查看相关链接,并与作者交流