umijs / qiankun

📦 🚀 Blazing fast, simple and complete solution for micro frontends.
https://qiankun.umijs.org
MIT License
15.83k stars 2.02k forks source link

[Bug]结合 styled components 使用时 dynamicHeadAppend 存在缺陷 #617

Closed xxn520 closed 4 years ago

xxn520 commented 4 years ago

What happens?

qiankun 和 styled components 一起使用时,当 styled components 插入动态样式时,样式量多时会为一个应用插入多个 style 节点,第一个 style 节点以后的 style 节点不是往 head 中插入的,因此 qiankun 的 dynamicHeadAppend 拦截不到。这导致在应用切换的时候,未拦截到的动态的 style 节点将会丢失,导致 styled components 报错。

相关环境信息

kuitos commented 4 years ago

styled components:0.4.4 ? 这个版本是不是太老了?

提供一个可复现仓库吧

xxn520 commented 4 years ago

4.4.0,5 以上也能复现。

xxn520 commented 4 years ago

仓库弄一个比较麻烦,晚点提供

xxn520 commented 4 years ago

其实就是目前 qiankun 拦截了动态往 head 里插的 style 节点,但是 styled components 第一个以后的动态 style 节点不是往 head 里插的,是往前面插入的最后一个 style 节点后面插的,因此拦截不到。

chenqiangmingyu commented 4 years ago

其实就是目前 qiankun 拦截了动态往 head 里插的 style 节点,但是 styled components 第一个以后的动态 style 节点不是往 head 里插的,是往前面插入的最后一个 style 节点后面插的,因此拦截不到。

@xxn520 问题解决了吗,能请教下解决方案么?也遇到相同问题,styled-components再rebuild的时候某些样式丢失了。

xxn520 commented 4 years ago

@chenqiangmingyu 升 5 目前能解决多个 style 节点带来的问题,但是升 5 后,在应用切换的时候,StyleSheet 里面的 Tag 里面的 sheet 对象持有的还是老的引用,会导致新的样式插不进去(这应该也就是你提到的某些样式丢失的原因),目前的解法是在应用卸载的时候调用一下 StyleSheet.clearTag 方法清空 Tag,那么在应用切回来的时候 Tag 会重新创建,sheet 对象也会更新。但是进一步会有新的问题,我们无法比较好的控制 clearTag 的时机,如果用了 styled components 的 global styles,这个东西卸载的时机如果在 clearTag 之后又会报新的错。总得来说这两个东西有点水土不服,可能会 fork 其中一个来改了。

kuitos commented 4 years ago

能提供一个可复现的仓库吗 @chenqiangmingyu @xxn520

xxn520 commented 4 years ago

@kuitos https://github.com/xxn520/qiankun/tree/master/examples 实际情况比这个复杂,但 dynamicHeadAppend 的问题这个例子也能够复现

chenqiangmingyu commented 4 years ago

能提供一个可复现的仓库吗 @chenqiangmingyu @xxn520

@kuitos @xxn520 我这边问题点已经fixed了,主要是子应用的容器是父应用动态生成的,父应用技术栈是React,因为父应用渲染由自身router控制,不受qiankun生命周期约束,导致location切换时把子应用的宿主容器给直接销毁,子应用unmount钩子执行与DOM容器清理并没有按照预期的顺序执行。容器清理后,待缓存的style节点也一并被粗暴的从DOM清理了,此后unmount读到的style可能由于gc之类机制出现了残缺(style.sheet === null),重建的样式也就异常了。

解决方案:这边把子应用容器作为一个常驻容器扔到父应用组件,不再销毁。 重建时产生另外一个问题就是cssRules和bootstrap的顺序正好相反造成的样式异常已经另开issue.

fantasyroot commented 4 years ago

@kuitos https://github.com/xxn520/qiankun/tree/master/examples 实际情况比这个复杂,但 dynamicHeadAppend 的问题这个例子也能够复现

+1,楼主这个是可复现仓库,请 @kuitos 能尽快解决,感谢

baicaisong commented 3 years ago

@chenqiangmingyu 升 5 目前能解决多个 style 节点带来的问题,但是升 5 后,在应用切换的时候,StyleSheet 里面的 Tag 里面的 sheet 对象持有的还是老的引用,会导致新的样式插不进去(这应该也就是你提到的某些样式丢失的原因),目前的解法是在应用卸载的时候调用一下 StyleSheet.clearTag 方法清空 Tag,那么在应用切回来的时候 Tag 会重新创建,sheet 对象也会更新。但是进一步会有新的问题,我们无法比较好的控制 clearTag 的时机,如果用了 styled components 的 global styles,这个东西卸载的时机如果在 clearTag 之后又会报新的错。总得来说这两个东西有点水土不服,可能会 fork 其中一个来改了。

@xxn520 请问StyleSheet.clearTag指的是子应用 unmount 的时候,把所有 <style> remove 吗?

https://stackoverflow.com/questions/53486470/react-styled-components-stripped-out-from-production-build

通过将 SC_DISABLE_SPEEDY=true ,可以使 <style> 里的内容在生产环境下也展示出来。可以避开 qiankun 在rebuildCSSRules 时对 styled components 的特殊处理。重新加载子应用时 styled components 也可以正确找到文件插入样式。可以解决我样式丢失的问题

li9269391 commented 2 years ago

@chenqiangmingyu 升 5 目前能解决多个 style 节点带来的问题,但是升 5 后,在应用切换的时候,StyleSheet 里面的 Tag 里面的 sheet 对象持有的还是老的引用,会导致新的样式插不进去(这应该也就是你提到的某些样式丢失的原因),目前的解法是在应用卸载的时候调用一下 StyleSheet.clearTag 方法清空 Tag,那么在应用切回来的时候 Tag 会重新创建,sheet 对象也会更新。但是进一步会有新的问题,我们无法比较好的控制 clearTag 的时机,如果用了 styled components 的 global styles,这个东西卸载的时机如果在 clearTag 之后又会报新的错。总得来说这两个东西有点水土不服,可能会 fork 其中一个来改了。

@xxn520 请问StyleSheet.clearTag指的是子应用 unmount 的时候,把所有 <style> remove 吗?

https://stackoverflow.com/questions/53486470/react-styled-components-stripped-out-from-production-build

通过将 SC_DISABLE_SPEEDY=true ,可以使 <style> 里的内容在生产环境下也展示出来。可以避开 qiankun 在rebuildCSSRules 时对 styled components 的特殊处理。重新加载子应用时 styled components 也可以正确找到文件插入样式。可以解决我样式丢失的问题

我也遇到了同样的问题。但项目里面用的是 css module ,SC_DISABLE_SPEEDY=true 是在哪里设置呢,是放在 umi 项目的根目录 .env 文件吗?我还尝试过加 REACT_APP_SC_DISABLE_SPEEDY=true 都不生效

jasonChen1234 commented 2 years ago

在umi-plugin-qiankun中,设置 sandbox:false 发现可以解决这个问题

li9269391 commented 2 years ago

@chenqiangmingyu 升 5 目前能解决多个 style 节点带来的问题,但是升 5 后,在应用切换的时候,StyleSheet 里面的 Tag 里面的 sheet 对象持有的还是老的引用,会导致新的样式插不进去(这应该也就是你提到的某些样式丢失的原因),目前的解法是在应用卸载的时候调用一下 StyleSheet.clearTag 方法清空 Tag,那么在应用切回来的时候 Tag 会重新创建,sheet 对象也会更新。但是进一步会有新的问题,我们无法比较好的控制 clearTag 的时机,如果用了 styled components 的 global styles,这个东西卸载的时机如果在 clearTag 之后又会报新的错。总得来说这两个东西有点水土不服,可能会 fork 其中一个来改了。

@xxn520 请问StyleSheet.clearTag指的是子应用 unmount 的时候,把所有 <style> remove 吗? https://stackoverflow.com/questions/53486470/react-styled-components-stripped-out-from-production-build 通过将 SC_DISABLE_SPEEDY=true ,可以使 <style> 里的内容在生产环境下也展示出来。可以避开 qiankun 在rebuildCSSRules 时对 styled components 的特殊处理。重新加载子应用时 styled components 也可以正确找到文件插入样式。可以解决我样式丢失的问题

我也遇到了同样的问题。但项目里面用的是 css module ,SC_DISABLE_SPEEDY=true 是在哪里设置呢,是放在 umi 项目的根目录 .env 文件吗?我还尝试过加 REACT_APP_SC_DISABLE_SPEEDY=true 都不生效

最后发现是 qiankun v2.7.2 更新导致,回退到v2.7.0正常