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

Suppress Safari class name mismatch warning #2569

Closed
wants to merge 10 commits into from

Conversation

srmagura
Copy link
Contributor

What: As discussed in #2534, runtime label extraction may fail in Safari due to Proper Tail Calls. This can result in hydration errors in development when using SSR and Safari.

Closes #2255.

Why: To shield innocent users from a confusing warning message.

How:

  • Add page to Next.js playground that reproduces the issue.
  • Override console.error in Safari only and suppress class name mismatch warnings that are likely the result of failed label extraction.
  • Add some unit tests. I resorted to testing implementation details because testing the whole thing is not really possible since console.error is not overridden in Node.
  • I didn't feel like messing with Flow so the new code is plain JS. Let me know if you want me to convert it to Flow.

Checklist:

  • Documentation N/A
  • Tests
  • Code complete
  • Changeset

Original Suggestion

This was originally proposed by @mitchellhamilton:

An idea for addressing the Safari issue: what if we overwrite console.error and don't call the real console.error warnings when we know they're fine?

Ideally we would even look at the content of the message, get the client side class name, look in the cache for the content for that, add label:LabelExtractedFromServerSideClassName;, hash it and compare the names and only skip it when they match so you'd still get the warning when it's correct

Unfortunately it is not possible to implement it like this because serialized styles are not always stored in cache.registered. See the insertStyles function.

@changeset-bot
Copy link

changeset-bot bot commented Nov 27, 2021

🦋 Changeset detected

Latest commit: e9ccdca

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@emotion/react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@codesandbox-ci
Copy link

codesandbox-ci bot commented Nov 27, 2021

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e9ccdca:

Sandbox Source
Emotion Configuration
react-ssr-bug Issue #2255

@codecov
Copy link

codecov bot commented Nov 27, 2021

Codecov Report

Merging #2569 (e9ccdca) into main (3d672ac) will decrease coverage by 0.49%.
The diff coverage is 79.76%.

Impacted Files Coverage Δ
...c/suppress-proper-tail-call-class-name-mismatch.js 78.75% <78.75%> (ø)
packages/react/src/emotion-element.js 100.00% <100.00%> (ø)
packages/utils/src/index.js 100.00% <100.00%> (ø)

- Fix bug: not handling non-Emotion class names
- Implement Andarist's suggestions
@srmagura
Copy link
Contributor Author

Thanks for the feedback @Andarist. I addressed all but one comment which I replied to.

@srmagura
Copy link
Contributor Author

srmagura commented Jan 16, 2022

Edit: Nevermind, I think I know how to solve this.

@Andarist @mitchellhamilton Hey, I made some progress on this but I have hit a snag.

Case 1

There are two caches, one with key emo and one with key css.

server class name: "emo-abc123-MyComponent css-abc123-MyComponent"
browser class name: "emo-def456 css-def456"

The hydration warning is caused by failed runtime label extraction and should be suppressed.

Case 2

server class name: "server-only-class css-abc123-MyComponent"
browser class name: "browser-only-class css-def456"

The hydration warning is caused by failed runtime label extraction AND a legit class name mismatch and therefore should not be suppressed.

Problem

My code should behave differently in Case 1 and Case 2. But how can I differentiate between them while only knowing about one Emotion cache at a time?

@srmagura
Copy link
Contributor Author

Sigh... This is done except for testing in IE, but I realized a major shortcoming of suppressing hydration warnings by overriding console.error.

Here is what I believe is a common situation:

render(
    <div>
        <ComponentForWhichRuntimeLabelExtractionFails />
        <ComponentThatRendersDifferentContentOnServerVersusBrowser />
    </div>
)

In this case, the second component causes a hydration warning that must be presented to the user.

We would be good if React called console.error for EACH hydration warning, but actually, React calls console.error only once, for the first hydration warning. My code blocks this call to console.error since it is a class name mismatch due to failed runtime label extraction. The end result is that no hydration warning is displayed, which is quite bad.

It seems like this completely invalidates the approach of overriding console.error... 🤔

@srmagura
Copy link
Contributor Author

@Andarist @mitchellhamilton

Following up on my previous comment, the best option I can think of now is to make runtime label extraction an optional feature. You could pass a runtimeLabelExtraction option to createCache and choose one of the following options:

  1. false — Disable runtime label extraction.
  2. true — Enable runtime label extraction.
  3. 'enableAndSuppressPtcHydrationWarnings' — Enable runtime label extraction and suppress hydration warnings in Safari (using the code contained in this PR). This is the "dangerous but convenient" option. Dangerous because it can suppress legit hydration warnings, convenient because you won't see unfixable hydration warnings. For browsers other than Safari, 'enableAndSuppressPtcHydrationWarnings' is equivalent to true.

Questions

  1. What should the default be? true to avoid changes to existing behavior?
  2. Should the default be changed in Emotion 12?

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.

Console error: Prop className did not match
3 participants