样式和脚本隔离
icestark 当下的方案里,无论是主应用还是微应用都是直接在页面里执行,本质上不存在隔离机制,针对这个问题我们一方面通过一些规范来保证污染问题,一方面也在尝试更加彻底的沙箱机制,如果你的微应用都是二方接入,那我们推荐直接通过规范约束即可,如果存在三方接入这种不可控的场景,建议还是通过 iframe 的方式嵌入。
#
样式污染页面运行时同时只会存在一个微应用,因此多个微应用不存在样式相互污染的问题,但是主应用和微应用是同时运行的,因此这两者中间可能会存在一些样式相互污染,针对这个问题,我们目前推荐「通过约定避免微应用与主应用的样式相互污染」的方案,同时也在尝试 Shadow DOM 的方案。
#
规范#
使用 CSS Modules 方案管理样式无论是主应用还是微应用,直接通过 CSS Modules 的方案管理自身可控的样式,这样基本杜绝了两者样式冲突的问题。
#
主应用自定义基础组件 prefix除了自身可控的样式,应用中还会有一些全局样式,比较典型的就是类似 next 这种基础组件的样式,如果主应用和微应用使用了不同版本的 next,则很容易造成样式相互污染,这种场景推荐在主应用中将基础组件的前缀统一改掉,比如将 next-
改为 next-icestark-
,这个能力已在主应用模板中内置,具体可参考相关代码。
#
微应用避免产生全局样式对于类似 normalize.css
这种全局重置样式,推荐统一通过主应用引入,微应用尽量避免产生全局性质的样式,因为这样在切换微应用时可能会因为全局样式差异产生一些抖动。
#
Shadow DOM(方案试验中)如果将微应用渲染到 Shadow DOM 中,那么微应用产生的所有样式都不会污染到全局,事实上在我们试验的过程中的确是这样的。但是我们遇到一个当下无法解决的问题,大部分类似 Dialog 组件的实现都是在 body 下创建一个容器节点,但是 Shadow DOM 里 Dialog 的样式无法作用到全局,因此展示出来 Dialog 就是无样式的,在这个问题上我们还在尝试,比如类似 Dialog 组件的实现能够进行优化:判断自身是否在 Shadow DOM 里,如果是的话则将容器节点创建到 Shadow DOM 里,否则创建到 body 节点下。
#
JS 污染相对于样式污染,JS 污染的危害性更高,在目前的方案下,如果微应用想要恶意污染的话基本是无法杜绝的,因此针对这种不可控的微应用建议还是通过 iframe 的方式接入。针对可控的二方应用,正常书写代码是不会有问题的,针对一些特殊情况我们也总结了一些规范。
#
规范#
微应用避免改变全局状态比如改变全局变量 window/location
的默认行为,通过 document
操作 Layout 的 DOM,这些本身都是一些不推荐的做法。
#
主应用通过钩子记录并恢复全局状态#
基于 Proxy 的运行沙箱通过 with + new Function
的形式,为微应用脚本创建沙箱运行环境,并通过 Proxy 代理阻断沙箱内对 window
全局变量的访问和修改。
icestark 内置了基于 @ice/sandbox
的沙箱隔离,通过 sandbox
属性开启: