Global component + advanced SSR doesn't hydrate as expected
See original GitHub issueCurrent behavior:
When using the “advanced approach” (https://emotion.sh/docs/ssr#advanced-approach) to SSR in combination with the <Global>
component, hydration doesn’t appear to be working as expected.
All non-global styles seem to be rehydrated properly, but styles included via <Global>
are injected into to the page when the client bundle hydrates instead of rehydrating the existing server-provided global styles.
This leads to issues due to specificity where the global rules now have a chance to override non-globals, causing visual bugs.
From looking at the source, this appears to be because InnerGlobal
checks if the global styles are already included on the page for rehydration purposes here: https://github.com/emotion-js/emotion/blob/c85378a204613885a356eaba1480c5151838c458/packages/core/src/global.js#L76
Unfortunately, this selector doesn’t match anything that would be produced by the “advanced approach” SSR guide, which suggests including:
<style data-emotion-css="${ids.join(' ')}">${css}</style>
on the page. So if the InnerGlobal
has this.props.serialized.name
of deadb33f
, it’s expecting to see:
<style data-emotion-css="deadb33f">...</style>
on the page to know where to hydrate, which isn’t the case. The reality will look more like:
<style data-emotion-css="deadb33f s0meId an0th3rOne">...</style>
To reproduce:
TODO: cannot use the codesandbox since it’s not set up for SSR. Will make a repo if this helps, but want to post this first since I do think I know roughly why it’s happening.
Expected behavior:
The styles included in <Global>
should be rehydrated in the same way as non-globals: i.e. any styles that are already included on the page via SSR should not be re-inserted.
I need to dig into how this is working for non-global styles, since presumably the logic is set up there to scan through the IDs included as part of the data-emotion-css
attribute rather than expecting a single id per style tag.
I’m also not sure if there’s an existing way to use extractCritical
to split up the css into multiple <style>
tags - it seems like that would also fix it from the other direction, although the docs would likely need to be updated if that’s the way forward.
Environment information:
react
version: 16.13.1@emotion/core
version: 10.0.35
Let me know if there’s any other info you need from me. I’ll try and spin up a repo if my snippets above don’t paint the full picture.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:7
- Comments:18 (10 by maintainers)
Top GitHub Comments
I’ve looked into the repro (thank you for that!) - need to give this some more thought, for now gonna just describe what happens here:
extractCritical
API we set automatically set the compat flag on the cache)<style/>
element.textContent
of<style/>
elements to remove those and we don’t do that now (and it’s also more complex/error-prone)yes, exactly