-
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
Nicer Formatting of SSR Validation #10085
Comments
Hi @sebmarkbage, Hi wanted to work on this issue, but I couldn't understand the info you gave above, also I am a beginner in React. Is this issue suitable for me to is there some docs that I should read to get up to speed with this codebase ... |
A general guide is here: https://facebook.github.io/react/contributing/how-to-contribute.html For this particular issue you'll probably want to most test it in the SSR fixture. It's a bit messy because you have to build React itself in the root before testing in fixture. https://github.com/facebook/react/tree/master/fixtures/ssr This issue is certainly not easy to get right but also doesn't that much existing knowledge of the code base. Just how React works with SSR. |
Hey, @sebmarkbage I'm trying to work on it. I'll probably have some questions, but overall it looks manageable. |
At a minimum, giving the |
Sry guys I've been busy at work this week. I'm trying to follow @sebmarkbage guide. It's still WIP, but now I have much more time for it. Two questions (sorry I'm a total newbie to the React codebase):
Is it fine, stupid, or something else? (Again sorry for a bit retarded question I'm really unsure as I'm not familiar with the codebase yet and want to deliver something useful.) Cheers. |
No question is silly. Can you please send a PR and we'll review it? @sebmarkbage is on a vacation now. |
@gaearon Thanks for the reply! OK, I will polish it a bit and open a PR, I'll be glad to get some feedback. |
Yea this is a bit confusing. Let me try to clarify. The existing diff mechanism will give you You'll notice that this is not called "attributeName" and the values passed are of type A way to visualize this is server-rendering this: Another one is Additionally when you format this text I'd expect the output to be JSX compatible, not HTML compatible. For example, self-closing tags like In fact, we'll likely want to experiment with other transfer formats than HTML and this visualization will transfer nicely to such environments. E.g. imagine React Native server rendering. Similarly text content's encoding can follow what you'd write in JSX, not what the encoding is in the HTML transfer format. Example: |
We should also probably pass the relevant Fiber's element source to the warnings. This way we can add information about where in the tree we are, similar to other warnings with component stacks. |
@gaearon There isn't just one Fiber that's responsible for the warning. Often it's many which is the point of this batched output. We could possibly include the component stack of the root most parent that failed and join them to create a whole tree view. Seems like it could get very noisy though. Isn't that better left to dev tools if you need a further tree view? |
My concern is it’s not always easy to find which |
@gaearon see my comment above. Using displayName where possible would dramatically ease finding the fragment of component hierarchy responsible for the issue. E.g
Instead of
|
It has the parent, which is at least some context. We only have the component stack from the client side but not the server side. One issue with showing too much context is that it can be misleading when something diffs because it doesn't line up correctly. E.g. often many different components will have nested divs that we will consider being a match because of the type but they're actually part of a different component. If we show the diff as part of a component tree, it'll look like the bug was within that component but in reality it was actually just the wrong component being rendered at a higher level. E.g. if App rendered
|
Hi, basically, I managed to get warning message looks like I created a HydrationWarningRenderer module which has the following method
I'd appreciate if anyone can let me know if this approach is worth of keeping working on. |
Another possible approach (browser-only): #7300 |
It would be nice to see this feature out. In React v15 the message was more explicit (I could tell which elements were different), but now it just says:
Also, now I'm having rendering issues due to this warning. I'm new to React codebase but I will try to give you a hand with this issue too. |
Sorry, we were focused on getting a release out, and didn't look into existing PRs yet. |
The last attempt at this was #10737 but we didn't review it in time and it grew stale. #7300 is a much simpler solution and maybe we should do something like this instead. If somebody wants to pick this up, let me know. It's not the easiest task so you should be relatively comfortable with working on your own, and discussing the proposed implementation in this issue before jumping to the code. In particular, you'll need to figure out which UX is the most ergonomic for this problem. |
Next, will add a test per every case.
Example warning: ``` Warning: Expected server HTML to contain a matching <em> in <div>. <div className="SSRMismatchTest__wrapper"> … <span className="SSRMismatchTest__2">2</span> <span className="SSRMismatchTest__3">3</span> <span className="SSRMismatchTest__4">4</span> <span className="SSRMismatchTest__5">5</span> <span className="SSRMismatchTest__6">6</span> - <strong> SSRMismatchTest default text </strong> + <em /> <span className="SSRMismatchTest__7">7</span> <span className="SSRMismatchTest__8">8</span> <span className="SSRMismatchTest__9">9</span> <span className="SSRMismatchTest__10">10</span> <span className="SSRMismatchTest__11">11</span> … </div> in em (at SSRMismatchTest.js:224) in div (at SSRMismatchTest.js:217) in div (at SSRMismatchTest.js:283) in SSRMismatchTest (at App.js:14) in div (at App.js:11) in body (at Chrome.js:17) in html (at Chrome.js:9) in Chrome (at App.js:10) in App (at index.js:8) ``` https://user-images.githubusercontent.com/498274/36351251-d04e8fca-145b-11e8-995d-389e0ae99456.png
Renders DOM attributes in the tags mentioned in the warnings. Borrows the idea and partially implementation of `getNodeSignature` from @giles-v facebook#12115 Renders DOM diff showing visually the location where the hydration failed. Example warning with a diff: ``` Warning: Expected server HTML to contain a matching <div>{['children ', …]}</div> in <div>nested<!-- --> <p>children <b>text</b></p></div>. <div> {'nested'} {' '} <p>children <b>text</b></p> + <div>{['children ', …]}</div> </div> in div (at SSRMismatchTest.js:280) in div (at SSRMismatchTest.js:275) in div (at SSRMismatchTest.js:308) in SSRMismatchTest (at App.js:14) in div (at App.js:11) in body (at Chrome.js:17) in html (at Chrome.js:9) in Chrome (at App.js:10) in App (at index.js:8) ``` Requires changes to ReactFiberReconciler interface functions that handle hydration errors to distinguish insertion from replacement and show insertion as one added line in the diff; show replacement as one removed, one added line, at correct position among the parentInstance's DOM children: - add `index` (use `fiber.index`) to point at which child node the insertion or replacement occurs; - add `isReplaced` to distinguish insertion from replacement. Extends the proof-of-concept at commit 6c425e7 https://user-images.githubusercontent.com/498274/36652198-11bb46fe-1a62-11e8-9fa2-a612827d1463.gif
…cebook#10085) - Change headline to contain only the tag names, not attributes and children. - Add newlines between headline, diff, and stack. Besides the above feedback: - Add comment nodes display in the diff. - Add weird node handling in the diff.
…cebook#10085) - Change headline to contain only the tag names, not attributes and children. - Add newlines between headline, diff, and stack. Besides the above feedback: - Add comment nodes display in the diff. - Add weird node handling in the diff.
* Add into existing fixture, not as a new one, to avoid duplicating server-rendering and hot-reloading code. * Add the browser-side counterpart for the `url` that was already passed to `render` at the server but wasn't used. Pass it down to the `App` component. Refs facebook#10085
…k#10085) - packages/react-dom: Add getStack (getCurrentFiberStackAddendum) to existing hydrate warnings in ReactDOMFiberComponent - packages/react-dom: Change two places where getCurrentFiberStackAddendum was called directly to getStack calls to unify its usages in ReactDOMFiberComponent - packages/react-dom: Add tests for all cases of hydrate mismatch warnings - fixtures/ssr: Add boolean prop values according to eslint rules of the core codebase in SSRMismatchTest - fixtures/ssr: Process SSRMismatchTest with prettier
Next, will add a test per every case.
Example warning: ``` Warning: Expected server HTML to contain a matching <em> in <div>. <div className="SSRMismatchTest__wrapper"> … <span className="SSRMismatchTest__2">2</span> <span className="SSRMismatchTest__3">3</span> <span className="SSRMismatchTest__4">4</span> <span className="SSRMismatchTest__5">5</span> <span className="SSRMismatchTest__6">6</span> - <strong> SSRMismatchTest default text </strong> + <em /> <span className="SSRMismatchTest__7">7</span> <span className="SSRMismatchTest__8">8</span> <span className="SSRMismatchTest__9">9</span> <span className="SSRMismatchTest__10">10</span> <span className="SSRMismatchTest__11">11</span> … </div> in em (at SSRMismatchTest.js:224) in div (at SSRMismatchTest.js:217) in div (at SSRMismatchTest.js:283) in SSRMismatchTest (at App.js:14) in div (at App.js:11) in body (at Chrome.js:17) in html (at Chrome.js:9) in Chrome (at App.js:10) in App (at index.js:8) ``` https://user-images.githubusercontent.com/498274/36351251-d04e8fca-145b-11e8-995d-389e0ae99456.png
Renders DOM attributes in the tags mentioned in the warnings. Borrows the idea and partially implementation of `getNodeSignature` from @giles-v facebook#12115 Renders DOM diff showing visually the location where the hydration failed. Example warning with a diff: ``` Warning: Expected server HTML to contain a matching <div>{['children ', …]}</div> in <div>nested<!-- --> <p>children <b>text</b></p></div>. <div> {'nested'} {' '} <p>children <b>text</b></p> + <div>{['children ', …]}</div> </div> in div (at SSRMismatchTest.js:280) in div (at SSRMismatchTest.js:275) in div (at SSRMismatchTest.js:308) in SSRMismatchTest (at App.js:14) in div (at App.js:11) in body (at Chrome.js:17) in html (at Chrome.js:9) in Chrome (at App.js:10) in App (at index.js:8) ``` Requires changes to ReactFiberReconciler interface functions that handle hydration errors to distinguish insertion from replacement and show insertion as one added line in the diff; show replacement as one removed, one added line, at correct position among the parentInstance's DOM children: - add `index` (use `fiber.index`) to point at which child node the insertion or replacement occurs; - add `isReplaced` to distinguish insertion from replacement. Extends the proof-of-concept at commit 6c425e7 https://user-images.githubusercontent.com/498274/36652198-11bb46fe-1a62-11e8-9fa2-a612827d1463.gif
…cebook#10085) - Change headline to contain only the tag names, not attributes and children. - Add newlines between headline, diff, and stack. Besides the above feedback: - Add comment nodes display in the diff. - Add weird node handling in the diff.
facebook#10085) When going through the fixtures one by one it's convenient to see the server-side rendered markup in the Chrome DevTools Elements along with the generated warning in Console. The placeholder element adds consistency to the markup: it does not disappear with page reloads, so Chrome DevTools is smart enough to keep it focused.
facebook#10085) When going through the fixtures one by one it's convenient to see the server-side rendered markup in the Chrome DevTools Elements along with the generated warning in Console. The placeholder element adds consistency to the markup: it does not disappear with page reloads, so Chrome DevTools is smart enough to keep it focused.
I think the label on this issue should be changed from "good first issue" to "good first issue (taken)" as I've been working on it for quite some time and reached quite some progress in here: #12063 |
I can work on this issue, if it's still open. Please let me know |
@joseantonjr I'm sorry but it's taken and almost done twice: here #12063 (this approach was abandoned after code review from the React Core team) and here #13602 (pending code review from the React Core team). |
Excited for this to be merged... SSR setup is finicky enough without having to debug |
After so much effort from @sompylasar, we still pocking around with the |
We didn't end up doing precisely this. However, we did add component stacks to hydration warnings in React 16.13: https://reactjs.org/blog/2020/03/02/react-v16.13.0.html#component-stacks-in-hydration-warnings That should get you most of the way there. They might still be occasionally misleading because the problem might be in one of the parent components rendering something unexpected. But they're much better than nothing. I think we can close this as other solutions are too complex. |
I don't think this should have been closed, because one of the goals was to show all warnings that happen on a pass, instead of just the first one that occurs. If there's interest in this, I'll be happy to be the one who removes the |
We're adding proper diffs in #28512. |
The new validation in #10026 only issues a warn for the first difference found in a HTML hydration scenario. Ideally it should instead queue up all the differences and then at the end (commit) issue a single warning with a nicely formatted diff.
Instead of warning add these warn calls to a global buffer (array, map, set, whatever).
Inside prepareForCommit, issue all the currently batched up warnings as a single message.
Format that message in terms of a JSX diff in a nicely formatted way. With only the relevant nodes (parent and child with changes). Irrelevant child content can be replaced with ellipsis. E.g.
This strategy won't yield perfect results because if we're asynchronously hydrating, and it gets interrupted by another tree, we'll flush a warning before the actual hydrating particular tree is flushed. So we might show a partial diff in that case. This is probably. It's just a warning.
The text was updated successfully, but these errors were encountered: