微前端能解决什么问题
- 大型项目复杂度高,打包时间长
- 团队协作技术栈不统一
- 增量迁移
微前端就是将不同功能按照不同维度拆分成多个子应用,通过主应用来加载子应用
如何实现微前端
我们可以将一个应用划分为若干个子应用,将子应用打包成一个个模块,当路径切换时加载不同的子应用
实现微前端需要解决哪些问题
- 数据间如何通信
- 应用间如何隔离(js隔离和css隔离)
实现方案
iframe
- 通过iframe加载子应用
- 通信可以通过postMessage进行通信
- 完美的沙盒机制自带应用隔离
缺点: 用户体验差(弹窗只能在iframe中、滚动条、内部切换刷新就会丢失状态)
web Components
- 将前端应用分解为自定义HTML元素
- 基于customEvent实现通信
- Shadow DOM天生作用域隔离
缺点:兼容性差、学习成本高、调试困难、修改样式困难
single-spa
- single-spa通过路由劫持实现应用加载,采用SystemJS加载应用或则模块
- 基于props主子应用通信
- 无沙盒机制,需要自己实现JS沙盒以及CSS沙盒
缺点: 学习成本、无沙盒机制,需要对原有的应用进行改造,子应用间相同资源重复加载问题
模块联邦
- 通过模块联邦将组件进行打包导出使用
- 共享模块的方式进行通信
- 无CSS沙盒和JS沙盒
systemJs
原理
- 动态扫描依赖映射表,加载依赖源
- 通过script动态导入打包好的子应用JS文件,加载好后,子应用会执行
System.register方法来注册子应用需要的依赖 - 动态加载子应用需要的依赖,加载完成后通过快照获取
windows上的全局依赖的对象 - 通过子应用的setter方法给子应用注入依赖
- 最后执行子应用的业务逻辑代码渲染子应用
single-spa
原理
- 基座应用是管理所有子应用的生命周期
- 基座在初始化的时候会注册子应用
- 当子应用的路由匹配到时,基座获取加载子应用的实例,然后获取并调用子应用的生命周期方法
- 通过
hashchange和popState监听路由变化,当路由变化时,基座会先卸载子应用,然后加载新的子应用,新的子应用加载完成后,会调用子应用的bootstrap、mount方法,渲染子应用
乾坤
TIP
乾坤微前端框架未采用SystemJS加载子应用,是多重因素交织作用的结果,涉及架构设计理念、应用隔离需求、资源加载效率及生态适配性等多个维度。以下从核心原因展开详细分析:
乾坤的核心设计目标之一是降低微前端接入成本,而SystemJS作为JavaScript模块加载器,其加载逻辑基于import语句,仅能处理JavaScript模块。相比之下,乾坤采用HTML Entry方案(通过import-html-entry库解析子应用的HTML入口),直接将HTML作为资源入口,可自动提取其中的CSS、JavaScript、图片等所有依赖资源,并按顺序加载执行。
这种方案的优势在于:
- 无需改造子应用:子应用无需遵循SystemJS的模块规范(如UMD、ES Module),只需提供标准HTML入口即可接入,极大降低了老项目或第三方应用的迁移成本;
- 资源加载更全面:HTML Entry可自动处理子应用的所有资源(包括CSS、图片、字体等),而SystemJS需手动管理这些资源的加载,增加了开发复杂度;
- 兼容性更好:HTML作为Web的标准入口,支持所有前端框架(React、Vue、Angular等),而SystemJS对非JavaScript资源的支持需额外配置。
微前端的核心需求之一是子应用间的隔离(JS沙箱、CSS隔离),而SystemJS本身不具备这些能力,需依赖外部库或手动实现。
乾坤通过沙箱机制彻底解决了这一问题:
JS沙箱:提供
SnapshotSandbox(快照沙箱,适用于低版本浏览器)、LegacySandbox(遗留沙箱,适用于单应用场景)、ProxySandbox(代理沙箱,适用于多应用场景)三种沙箱方案,通过Proxy或快照技术隔离子应用的window对象,避免全局变量污染;CSS隔离:提供
strictStyleIsolation(严格样式隔离,通过Shadow DOM实现)、experimentalStyleIsolation(实验性样式隔离,通过CSS前缀实现)两种方案,彻底隔离子应用的样式,避免样式冲突。相比之下,SystemJS需结合
single-spa-css等外部库实现CSS隔离,且JS隔离需手动管理window对象,增加了开发和维护成本。
乾坤的资源加载机制更符合微前端的动态性需求:
动态加载:通过
import-html-entry解析子应用的HTML入口,动态加载其JavaScript和CSS资源,无需提前打包所有子应用,减少了主应用的体积;预加载优化:支持
prefetch策略(如visible(可见时预加载)、all(全部预加载)),提前加载子应用的资源,提升应用切换的流畅性。而SystemJS的加载逻辑基于
System.import,需手动管理资源的加载顺序和依赖关系,且预加载支持较弱,无法满足微前端的高性能需求。
在微前端里如何实现css隔离
css-module,vue的scopedshadowDOM天然的作用域隔离
乾坤css隔离原理:属性选择器原理同理于vuescoped样式隔离
缺点:子应用的元素不能动态挂载到基座的元素上,会有样式丢失的问题。
shadowDOM原理:把子应用打包动态渲染到shadowDOM的标签元素中,shadowDOM有天然的样式隔离。
js沙盒proxy代理处理window隔离:
1.在a应用渲染前新建一个沙盒,把沙盒的代理作为window传给子应用,在a应用的副作用中可能会在windows上挂载一些沙盒属性,可以通过proxy代理劫持修改或者新增属性,存储到沙盒中,在子应用切换的时候还原windows上的属性,同理在子应用b上做相同的操作。最后在a应用重新激活的时候把沙盒中的修改和新增的属性重新加回到windows上。
缺点:ab应用一起渲染的时候只有一个windows就错乱了。
最终优化方案:多沙盒代理模式
为每一个应用创建单独的沙盒,通过proxy代理一个空对象,如果应用中要获取window上的属性先从proxy空对象中获取没有再从window上获取,如果应用要修改window上属性直接修改proxy代理对象的属性,这样就不会污染window,如果在应用失活的时候通过变量组织代理对象的修改。