首页 前端知识 微服务之间的js隔离和css隔离实现原理

微服务之间的js隔离和css隔离实现原理

2024-07-30 22:07:28 前端知识 前端哥 74 605 我要收藏

文章目录

      • JS隔离
        • 【降级处理】SnapshotSandbox快照沙箱
        • 代理沙箱:legacySandbox单例沙箱
        • 【qiankun主要方式】代理沙箱:proxySandbox多例沙箱
      • CSS隔离
        • Shadow DOM
        • CSS模块(CSS Modules)
        • 样式表的装载和卸载
        • 样式隔离踩坑记

JS隔离

JS 沙箱简单点说就是,主应用有一套全局环境 window,子应用有一套私有的全局环境 fakeWindow,子应用所有操作都只在新的全局上下文中生效,这样的子应用好比被一个个箱子装起来与主应用隔离,因此主应用加载子应用便不会造成 JS 变量的相互污染、JS 副作用、CSS 样式被覆盖等,每个子应用的全局上下文都是独立的。

【降级处理】SnapshotSandbox快照沙箱

快照沙箱就是在应用沙箱挂载和卸载的时候记录快照,在应用切换的时候依据快照恢复环境。
缺点,无法同时有多个运行时快照沙箱,否则在 window 上修改的记录会混乱,一个页面只能运行一个单实例微应用

基于diff来实现的,主要用于不支持window.Proxy的低版本浏览器,而且也只适应单个的子应用

原理: 激活沙箱时,将window的快照信息存到windowSnapshot中, 如果modifyPropsMap有值,还需要还原上次的状态;激活期间,可能修改了window的数据;退出沙箱时,将修改过的信息存到modifyPropsMap里面,并且把window还原成初始进入的状态。

  • 微应用 mount 时
    先把上一次记录的变更 modifyPropsMap 应用到微应用的全局 window,没有则跳过
    浅复制主应用的 window key-value 快照,用于下次恢复全局环境
  • 微应用 unmount 时
    将当前微应用 window 的 key-value 和 快照 的 key-value 进行 Diff,Diff 出来的结果用于下次恢复微应用环境的依据
    将上次快照的 key-value 拷贝到主应用的 window 上,以此恢复环境

优缺点分析: snapshotSandbox会污染全局window,但是可以支持不兼容Proxy的浏览器

在这里插入图片描述

代理沙箱:legacySandbox单例沙箱

当有多个实例的时候,比如有 A、B 两个应用,A 应用就活在 A 应用的沙箱里面,B 应用就活在 B 应用的沙箱里面,A 和 B 无法互相干扰,这样的沙箱就是代理沙箱,这个沙箱的实现思路其实也是通过 ES6 的 proxy代理特性实现的。
缺点:在全局作用域上通过 var 或 function 声明的变量和函数无法被代理沙箱劫持,因为代理对象 Proxy 只能识别在该对象上存在的属性,通过 var 或 function 声明声明的变量是开辟了新的地址,自然无法被 Proxy 劫持

基于es6的Proxy实现

原理:legacySandbox设置了三个参数来记录全局变量,分别是记录沙箱新增的全局变量addedPropsMapInSandbox、记录沙箱更新的全局变量modifiedPropsOriginalValueMapInSandbox、持续记录更新的(新增和修改的)全局变量,用于在任意时刻做snapshot的currentUpdatedPropsValueMap。

通过监听对 window 的修改来直接记录 Diff 内容,因为只要对 window 属性进行设置,那么就会有两种情况:

  • 如果是新增属性,那么存到 addedMap 里
  • 如果是更新属性,那么把原来的键值存到 prevMap,把新的键值存到 newMap

通过 addedMap, prevMap 和 newMap 这三个变量就能反推出微应用以及原来环境的变化,qiankun 也能以此作为恢复环境的依据。在这里插入图片描述

【qiankun主要方式】代理沙箱:proxySandbox多例沙箱

原理:激活沙箱后,每次对window取值的时候,先从自己沙箱环境的fakeWindow里面找,如果不存在,就从rawWindow(外部的window)里去找;当对沙箱内部的window对象赋值的时候,会直接操作fakeWindow,而不会影响到rawWindow。

  1. 把当前 window 的一些原生属性(如document, location等)拷贝出来,单独放在一个对象上,这个对象也称为 fakeWindow
  2. 之后对每个微应用分配一个 fakeWindow
  3. 当微应用修改全局变量时:
    如果是原生属性,则修改全局的 window
    如果不是原生属性,则修改 fakeWindow 里的内容
  4. 微应用获取全局变量时:
    如果是原生属性,则从 window 里拿
    如果不是原生属性,则优先从 fakeWindow 里获取

这样一来连恢复环境都不需要了,因为每个微应用都有自己一个环境,当在 active 时就给这个微应用分配一个 fakeWindow,当 inactive 时就把这个 fakeWindow 存起来,以便之后再利用。
优缺点分析:不会污染全局window,支持多个子应用同时加载。
在这里插入图片描述

CSS隔离

Shadow DOM

qiankun主要通过使用Shadow DOM来实现CSS隔离。

Shadow DOM:Shadow DOM是一种浏览器内置的Web标准技术,它可以创建一个封闭的DOM结构,这个DOM结构对外部是隔离的,包括其CSS样式。qiankun在挂载子应用时,会将子应用的HTML元素挂载到Shadow DOM上,从而实现CSS的隔离

// qiankun使用Shadow DOM挂载子应用
const container = document.getElementById('container');
const shadowRoot = container.attachShadow({mode: 'open'});
shadowRoot.innerHTML = '<div id="subapp-container"></div>';

潜在的缺点是它需要浏览器支持Shadow DOM,这在一些旧的浏览器或者不兼容Shadow DOM的浏览器中可能会出现问题。
在这里插入图片描述

CSS模块(CSS Modules)

CSS模块是一种将CSS类名局部化的方式,可以避免全局样式冲突。在使用CSS模块时,每个模块的类名都会被转换成一个唯一的名字,从而实现样式的隔离。qiankun 可以帮助自动化这个过程,但是它需要子应用在构建时合作,即在构建过程中将所有的类名前加上特定的字符串。

样式表的装载和卸载

当切换到一个子应用时,qiankun 动态加载这个子应用的样式文件,并在切换离开这个子应用时卸载它的样式文件。这样可以确保只有当前活动的子应用的样式会被应用。

样式隔离踩坑记

elementUI组件的一些弹窗默认是挂载到 body 上的,这就导致了再使用微前端集成的时候,子应用的弹窗逃逸,导致无法控制其弹窗的样式。

解决办法:先给组件全局配置一个 content 属性,接受需要挂载容器的 ID
然后利用计算属性,获取全局挂载容器,然后把默认的 document.body 替换成全局的挂载容器就可以简单的实现。

转载请注明出处或者链接地址:https://www.qianduange.cn//article/14617.html
标签
微服务
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!