Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 修复styled-components兼容性问题 #2606

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Aeero
Copy link

@Aeero Aeero commented Aug 18, 2023

Checklist
  • npm test passes
  • tests are included
  • documentation is changed or added
  • commit message follows commit guidelines
Description of change

@vercel
Copy link

vercel bot commented Aug 18, 2023

Someone is attempting to deploy a commit to a Personal Account owned by @umijs on Vercel.

@umijs first needs to authorize it.

Copy link
Member

@kuitos kuitos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

没看懂,这个修复是怎么 work 的?
styled-component 的问题在于 recordStyledComponentsCSSRules 在调用时,因为 styleElement 可能已经被从文档上移除了,导致 styleElement.sheet.cssRules 获取到的是空的。这个 pr 劫持了 insertRule 这些方法,但没看到怎么记录的,而且这个时候应用已经在卸载了,劫持起不到任何效果了。

@Aeero
Copy link
Author

Aeero commented Aug 21, 2023

没看懂,这个修复是怎么 work 的? styled-component 的问题在于 recordStyledComponentsCSSRules 在调用时,因为 styleElement 可能已经被从文档上移除了,导致 styleElement.sheet.cssRules 获取到的是空的。这个 pr 劫持了 insertRule 这些方法,但没看到怎么记录的,而且这个时候应用已经在卸载了,劫持起不到任何效果了。

"styled-component 的问题在于 recordStyledComponentsCSSRules 在调用时,因为 styleElement 可能已经被从文档上移除了,导致 styleElement.sheet.cssRules 获取到的是空的",这个问题我暂时没有复现过,styleElement.sheet.cssRules一直都是有的,我并不是要解决cssRules为空的问题。

这个PR要解决的是style节点从document移除,然后rebuil之后styleElement.sheet引用变动导致新增样式失效的问题。举个例子,document上有一个style节点style1,sheet1 = style1.sheet,然后移除style节点再重新插入到document上(模拟应用切换style重建的过程),此时style1.sheet和sheet1是不相等的。然后styled-components内部只会记录sheet1,后续动态的样式只会往sheet1里插入,所以后续的样式都失效了。此PR拦截了sheet1的insert的逻辑,插入到重建后的style节点上,这样后续的动态样式就能生效了。

@kuitos
Copy link
Member

kuitos commented Aug 21, 2023

明白了。
不过这样也只是修复了 styled component 的一个问题,我提到的那个问题会更常见一些,看上去还是没解决。这样的话现阶段更推荐通过关闭 cssom 来规避 styled component 引入的问题了。

@Aeero
Copy link
Author

Aeero commented Aug 21, 2023

没看错的话切换应用清除dom用的应该是render({ element: null, loading: false, container: remountContainer }, 'unmounted');,然后recordStyledComponentsCSSRules 应该是在unmountSandbox时被触发的。
顺序上unmountSandbox应该始终是早于清除dom的逻辑的
image
什么情况下会复现你说的这个问题呀

@kuitos
Copy link
Member

kuitos commented Aug 21, 2023

比如主应用也监听了路由,路由变化的时候立马清空了容器 DOM,而 unmount 过程是异步的,这中间就可能出现子应用还在 unmount 执行过程中,但是 DOM 其实都已经被移除 document 文档流了。

@Aeero
Copy link
Author

Aeero commented Aug 21, 2023

确实会有这样的情况。
如果是把拦截insert的逻辑放到子应用appendChildOrInsertBefore style节点的时候是不是能解决这个问题。

@kuitos
Copy link
Member

kuitos commented Aug 21, 2023

理论上是可行的,如果 styled component 都是通过 insertRule 在插入样式的话,可以劫持过程中记录一把。

@kuitos
Copy link
Member

kuitos commented Aug 30, 2023

hi @Aeero 按照前面聊的思路,提前记录一把应该是可行的,有兴趣直接一起修复了吗?

@Aeero
Copy link
Author

Aeero commented Aug 30, 2023

hi @Aeero 按照前面聊的思路,提前记录一把应该是可行的,有兴趣直接一起修复了吗?

嗯嗯,按照这个思路改过几版,但是还是有一些没有解决的问题,所以暂时还是WIP,大佬有空可以帮忙review一下这几个问题和解决思路

  1. 如果改成 appendChildOrInsertBefore 时提前记录,则没法用isStyledComponentsLike判断是否是styled-components节点,因为style节点刚插入的时候大概率都是一个空节点,在一开始的时候很难判断是否会发展成StyledComponentsLike节点。这个问题想到两个解决方法:a.动态插入的style节点全都做sheet拦截和记录,但是如果是非StyledComponentsLike节点就有点多余(应该不会有sheet.insertRule和children混合用的情况吧)。 b. 使用hasAttribute('data-styled-version')判断是否是styled-components节点,但是相当于范围收窄了,可能会有一点berak change。

  2. https://github.com/umijs/qiankun/issues/1533,同样也是遇到了这个问题。css in js的库通过lastStyleTag.parentNode.insertBefore插入节点,这样不会被appendChildOrInsertBefore拦截,也就不会被记录成动态节点。解决思路是重写qiankunHead.append qiankunHead.insertBefore appWrapper.appendChild 改成 document.head.appendChild document.head.insertBefore document.body.appendChild,这样就能被appendChildOrInsertBefore拦截了

  3. 没有上述修改的情况下,react.Suspense fallback了一个styled-components包裹的dom(无论是texttag还是cssomtag),safari下偶现子应用第一帧样式丢失的问题,可能是我业务的问题,还没头绪,如果大佬有遇到类似的问题可以帮忙贴一下相关信息,非常感谢

@kuitos
Copy link
Member

kuitos commented Aug 31, 2023

  1. isStyledComponentsLike 里加一个 hasAttribute('data-styled-version') 应该没问题,相当于多了一个判断条件,做成 || 应该就行,不会有 breaking change
  2. 这个不打算在 2.x 里支持了,影响比较大,挪到 3.x 考虑吧
  3. 是子应用二次进入的时候丢失了吗?texttag 模式下不太可能出现这个问题🤔

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

styled-components CSSOM模式 应用切换样式丢失问题
2 participants