-
Notifications
You must be signed in to change notification settings - Fork 47k
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 false positive hydration warning for SVG attributes #10676
Conversation
}); | ||
|
||
itRenders( | ||
'svg child element with a namespace attribute', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an old test. I just renamed it and moved down.
@nhunzaker Are there any other cases where this could happen? Do you remember why it didn't use |
I do not know why |
@@ -912,7 +912,7 @@ var ReactDOMFiberComponent = { | |||
case 'selected': | |||
break; | |||
default: | |||
extraAttributeNames.add(attributes[i].name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was intentional so that you would compare and display it in the case that it was received. For things like SVG where case matters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is right because on SVG we do want things like <svg foobar="" />
vs. <svg fooBar="" />
to show up as an extra attribute.
It might make sense to deal with this at the same time as the "all attributes should be lower-case" warning though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure that we can, unless we can control for browsers that report casing from attribute.name
inconsistently. For example, IE Edge reports SVG fill
and `stroke in all caps:
Test: https://codepen.io/nhunzaker/pen/qXRPvY
Screenshot of IE Edge 15:
Screenshot of Chrome:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nhunzaker Can we special case the known ones since they will also have the warning about invalid case of the prop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can start to compile a list of special cases. I'm sort of worried that this will be tedious and it'll end up being most of SVG, but I don't know that yet. I know of differences in casing of SVG in IE Edge. I didn't know about the cases alluded to in Chrome.
Should I just open up the attribute table in every browser using BrowserStack? How many versions back should I go?
Kind of makes me wonder if it could be automated using their remote API.
I have a few questions, and I apologize in advance if they sound cynical, but I don't want to assume anything so I can better understand the problem:
1: What is the advantage to case-sensitive hydration? Casing warnings for known attributes will raise server-side during markup generation (is this correct?), and then and on update client-side.
2: Wouldn't the same components consistently misspell attribute names server and client side?
3: Even if the casing is produced differently server/client-side, browsers don't appear to care about casing. I'm curious if this is generally true, or if my tests are flawed. They certainly aren't exhaustive.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My concern is that just ignoring case doesn't take the core of the problem in to consideration because it's not the case that browsers completely ignore case. There are specific rules for it.
Specifically, the rules (other than bugs/quirks like the IE thing) is that the HTML parser of a server response makes them lower-case except for a whitelist. https://www.w3.org/TR/html5/syntax.html#adjust-svg-attributes
However, this whitelist doesn't apply to client code. Specifically cases like this is what I'm concerned about:
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('viewbox', '0 0 1 1');
console.log(svg.viewBox);
var container = document.createElement('div');
container.innerHTML = '<svg viewbox="0 0 1 1"></svg>';
console.log(container.firstChild.viewBox);
Rendering the "viewbox" attribute on the server and the client behaves differently because it is case-sensitive on the client but not on the server.
So simple saying that they're not case-sensitive is not the full story. It might be the case that this is the best compromise anyway but I want to make sure we've considered all the aspects because "DOM is case-insensitive" is an oversimplification so we might be missing something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah got it. So there are attributes that care about casing. That's frustrating...
Thank you for spelling this out for me. Prior to this point, I was not aware of the differences between HTML/SVG parsing and the DOM attribute manipulation. What a mess!
FYI, this is tangental to this PR but there are a few attributes in the attribute tables that correctly warns because they're buggy in Chrome. Chrome doesn't turn them into camelcase like it should. There are also some that are incorrectly left out of the HTML parsing spec. If we get a report for that, be careful to look into it. |
Oh, and if you render |
Hmm. Is new test I added wrong then? It used to fail before this PR. But it uses correct casing ( |
I think your test is correct because it is a known one. However, we have to be careful when we look at these things because if it wasn't known then we'd warn that you should use lower case (if we add the lowercase warning). That would work with SSR and hydration but not if it was only rendered on the client. E.g. during an update. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the real bug is at line 1011. https://github.com/facebook/react/pull/10676/files#diff-9756d35a2f408667aa5e1cfb065b4fdcR1011
It should do toLowerCase
for HTML, but not for SVG and it probably needs to be special case aware.
I started looking into it but didn’t get far. It will take me a while to understand the constraints here again. If either of you have better insight into the best fix feel free to take this; otherwise I will continue tomorrow. I could also apply the fix in #10676 (review) but I don’t know which special cases the fix should be aware of. |
Pushed up a version that threads the parent namespace through for the check. Could also read it from the element. Is it enough for the most narrow fix to unblock this? We can fix edge cases with IE later. |
// $FlowFixMe - Should be inferred as not undefined. | ||
extraAttributeNames.delete(propKey.toLowerCase()); | ||
let ownNamespace = parentNamespace; | ||
if (ownNamespace === HTML_NAMESPACE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why rename parentNamespace
to ownNamespace
here instead of using parentNamespace
directly or setting ownNamespace
as the argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disregard. Sorry I didn't catch the code below.
} | ||
if (ownNamespace === HTML_NAMESPACE) { | ||
// $FlowFixMe - Should be inferred as not undefined. | ||
extraAttributeNames.delete(propKey.toLowerCase()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's worth adding a comment for why we need to downcase the propKey (because HTML reports lowercase, right?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This makes sense to me, the only edge case I can think of is if the casing reporting behavior is inconsistent across SVG attribute names.
I would be okay with making that a follow up to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine but I think we'll also need a follow up (which may very well be something case insensitive for unknown but case sensitive for known or something like that).
} else { | ||
// $FlowFixMe - Should be inferred as not undefined. | ||
extraAttributeNames.delete(propKey); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This made me realize that we probably don't validate that two components with the same name but different namespaces line up in the hydration. I'm not sure there's a way to get that wrong in another way than innerHTML SVG content in a HTML root.
Would that follow up be blocking to 16 release? |
Fixes #10672.
The new test used to fail but now passes.