为什么是qiankun而不是iframe
- 无法保持路由状态,刷新后路由状态就丢失(这点也不是完全不能解决,可以讲路由作为参数拼接在链接后,刷新时去参数进行页面跳转)
- 完全的隔离导致与子应用的交互变得极其困难
iframe
中的弹窗无法突破其本身- 整个应用全量资源加载,加载太慢
qiankun原理
当路由切换的时候,去下载对应应用的代码,然后跑在容器里,qiankun 只是对 single-spa 的升级。 它升级了啥东西呢?第一个就是入口,改为了 html 作为入口,解析 html,从中分析 js、css,然后再加载,这个是 import-html-entry 这个包实现的。它是把 js 代码包裹了一层 function,然后再把内部的 window 用 Proxy 包一层,这样内部的代码就被完全隔离了,这样就实现了一个 JS 沙箱。就是 function 包裹了一层,所以代码放在了单独作用域跑,又用 with 修改了 window,所以 window 也被隔离了。
qiankun、wujie、micro-app 的区别主要还是实现容器(或者叫沙箱)上有区别,比如 qiankun 是 function + proxy + with,micro-app 是 web components,而 wujie 是 web components 和 iframe。
实现window隔离的原理
当我们在 JS 文件里有 window.a = 1
时,实际上会变成:
function fn(window, self, globalThis) {
window.a = 1;
}
const bindedFn = fn.bind(window.proxy);
bindedFn(window.proxy, window.proxy, window.proxy);
那么此时,window.a
的 window
就不是全局 window
而是 fn
的入参 window
了。又因为我们把 window.proxy
作为入参传入,所以 window.a
实际上为 window.proxy.a = 1
。这也正好解释了 qiankun 的 JS 隔离逻辑。
qiankun坑点
样式隔离
不启用样式隔离 父子,子子 应用的样式相互影响
解决方案
自己选择命名方案避免影响
qiankun方案-shadow dom
sandbox: {
strictStyleIsolation: true,
}
主应用的样式和使用了strictStyleIsolation的子应用样式互不影响,但样式继承可以影响到
但是会导致弹窗的样式挂掉,因为弹窗默认是挂在 body 上的,也就不在 shadow dom 里了,那 shadow dom 里给它加的样式自然就不生效了。 那弹窗的样式问题怎么解决? 是通过通信机制把弹窗样式传过去么?那是不是改造成本又增加了? 所以 qiankun 的 shadow dom 的样式隔离方案是有问题的。
qiankun方案-scoped css
sandbox: {
experimentalStyleIsolation: true,
}
它是怎么做的样式隔离呢?
借鉴了 scoped css 的思路。
也就是对所有样式加了一层 data-qiankun=“应用名” 的选择器来隔离:
这样其他应用的样式能影响子应用了
但是子应用的样式还是影响不了父应用,看上面的弹窗就知道了。
为什么呢?
因为子应用里所有的样式都加了 data-qiankun 的限制,那就影响不了子应用外部了,所以挂在 body 的弹窗还是挂掉了加不了样式。
有同学说,那支持声明 global 样式不就行了?
问题就在这,qiankun 并没有实现这个功能。 所以 qiankun 的 scoped css 的样式隔离方案也是有问题的。
而 react 和 vue 项目本身都会用 scoped css 或者 css modules 的组件级别样式隔离方案,这俩方案都支持传递样式给子元素、设置全局样式等,只是实现和使用方式不同。
现在的 vue、react 项目基本都做了组件样式隔离了,有点全局样式也是可控的,真没必要用 qiankun 的那个。
qiankun 的样式隔离方案比较坑,能不用就别用吧。