几种微前端框架的沙箱策略
1.qiankun框架
css隔离方案:
1.Shadow DOM:
将子应用的Dom挂载到一个shadow root 内,这样的话Shadow root 内的dom节点与外部的dom是完全隔离开的,这样就做到了完全隔离
2.Scoped css:
将所有样式增加唯一前缀,比如说使用class选择器,添加唯一的名字,这个唯一的class 选择器所添加的样式,就不会被任何别的样式所影响
注意点:对于Scoped css隔离方案,如果有动态添加的样式或者说来自于第三库暂未隔离的样式,需要做一些处理。
如果动态添加的是内联样式,那么它本来就是天然唯一的,不用做处理
如果是添加了dom上自定义了class,那么可以通过mutationObserver来监听dom的变化,实现样式添加的拦截,为class加上后缀
如果添加的是样式表,那么只要拦截添加操作,在样式表的样式中将相关的样式增加前缀
3.动态样式表管理优化:
这个是qiankun框架对css隔离方案的优化,将所有样式放进样式表中,当加载子应用时,就加载子应用的样式表。卸载子应用时,就卸载子应用的样式表 ,当然了这只是加载方案,任然需要上面两种方案的配合才能实现样式隔离、
js隔离方案:
1.快照沙箱:
基座应用初始化时,保存原本的window对象,每次加载子应用时,子应用都会有新的window对象,这时候会做替换,当修改了子应用的某些内容时,这次子应用的window 会跟上一次的子应用自己的window 对比,保存新增加的内容,当卸载子应用时,恢复基座应用的window。
其实就是不同应用加载不一样的window对象,然后同时window对象会更新,如果卸载了某个应用,就把window对象恢复成原来的
快照沙箱的问题:每次只能同时运行一个子应用,因为window对象始终只有一个,相当于单例模式
2.代理沙箱:
通过es6 的proxy 拦截window 的所有操作,不同子应用都有它自己的global对象,当操作window时,window上的操作都会拦截到对应的global对象上,当卸载子应用时,global对象清空即可,由于只是拦截操作,global对象可以有很多个,所以可以同时运行多个子应用
注意点:为什么做js拦截需要关注window对象?
这是由于js的大部分操作都需要window全局对象来控制,比如说dom操作bom操作,他们的事件都是挂载到全局window上的,另外最基本的var变量,他的变量声明后都挂在到window上,所以为了互不干扰,必须要对window对象操作。简单来说,一个window他代表了一个页面
2.EMP框架
EMP框架主要借助webpack5的联邦模块,这里主要讨论模块联邦
模块联邦,其实就是相当于分包拆包,把某个模块单独拆分出去,打包成一个js,当然了这样的代码,肯定都是完全没有js隔离和样式隔离的,所有的隔离沙箱都得自己想办法实现。具体的实现方式肯定就参考上面qiankun的实现
3.wujie框架
无界框架采用webcomponent+iframe 沙箱的机制
对于webcomponent,上面提到的shadow dom 本来也就是webcomponent的一部分,所以这个框架,必然可以实现css隔离。
js隔离则是采用的iframe。
wujie将js代码放到一个和当前同源的iframe中,此时当前应用的操作就可以访问到iframe里的js,由于同源策略,他们具有同一个浏览器上下文。此时所有的js,在iframe中则是完全隔离的,接着使用proxy把iframe中的所有操作代理到相对应的webcomponet中,完美的实现了js隔离和样式隔离
4.microApp
microApp,也沿用了webcomponent的思路,最开始,microApp的隔离方案为webcomponent隔离样式,使用跟qiankun一样的快照沙箱和代理沙箱隔离js。后来又参考了wujie,升级了iframe沙箱方案
5.iframe
iframe 可以说是早期的微前端,方案,他能做到完美且完全的js隔离和样式隔离。
但他缺点也很多,他就相当与一个新的网页,挂进了当前网页中,缺点如下:
1.通信困难:当iframe不与主应用同源时,只可以使用postMessage通信,且postMessage只可以传送字符串,数字,普通对象,数组。dom节点函数等一些特殊的数据都不可以传递,且postMessge必须指定目标域名,如果应用域名变动,还得手动维护
2.dom隔离,父子应用都不能互相操作dom,导致如果有一个全局弹窗,他只能显示在iframe内部,路由状态丢失,主应用是主应用的路由,子应用是子应用的路由,主应用回退,子应用不会差生什么变化
3.白屏时间太长,每次都是解析一个网页,他都要对每个iframe再次构建浏览器上下文,这个时间会耗时比较长,那么会导致用户等待过久