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

ReactDOM renderToString adds empty HTML comments #14725

Closed
buildbreakdo opened this issue Jan 30, 2019 · 5 comments
Closed

ReactDOM renderToString adds empty HTML comments #14725

buildbreakdo opened this issue Jan 30, 2019 · 5 comments

Comments

@buildbreakdo
Copy link

buildbreakdo commented Jan 30, 2019

Do you want to request a feature or report a bug?
Bug

What is the current behavior?
ReactDOM.renderToString adds an empty HTML comment.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:

const someVar = 'foo';

const htmlWithVariableAndCharacters = document.createTextNode(
  ReactDOMServer.renderToString(
    <div>{someVar}anyCharacters</div>
  )
);

document.body.appendChild(htmlWithVariableAndCharacters);

HTML Output:

<div data-reactroot="">foo<!-- -->anyCharacters</div>

See it live here: https://codepen.io/anon/pen/mvORKd?editors=0010

What is the expected behavior?
Expected HTML output:

<div data-reactroot="">fooanyCharacters</div>

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
Seen in React 16.7.0, do not know behavior in previous versions.


Something to keep in mind is if you open Chrome Development Tools you will not be able to see these HTML comments as Chrome strips them from being viewed in the developer pane. They can be seen in a server side render string output or if you right-click and choose 'Copy Element' and paste into a text editor.

@buildbreakdo buildbreakdo changed the title ReactDOM renderToString adds HTML comment ReactDOM renderToString adds empty HTML comment Jan 30, 2019
@buildbreakdo buildbreakdo changed the title ReactDOM renderToString adds empty HTML comment ReactDOM renderToString adds empty HTML comments Jan 30, 2019
@gaearon
Copy link
Collaborator

gaearon commented Jan 30, 2019

This is by design and helps React hydrate those text nodes correctly.

@gaearon gaearon closed this as completed Jan 30, 2019
@buildbreakdo
Copy link
Author

@gaearon Oh, very interesting.

Note for folks that somehow land here, if you want to avoid the extra characters, particularly in long lists of things which can add up to thousands of characters can switch from something like:

Before

const someVar = 'foo';

const htmlWithVariableAndCharacters = document.createTextNode(
  ReactDOMServer.renderToString(
    <div>{someVar}anyCharacters</div>
  )
);

document.body.appendChild(htmlWithVariableAndCharacters);
// Output: <div data-reactroot="">foo<!-- -->anyCharacters</div>

After

const htmlWithVariableAndNoCharacters = document.createTextNode(
  ReactDOMServer.renderToString(
    <div>{`${someVar}anyCharacters`}</div>
  )
);

document.body.appendChild(htmlWithVariableAndNoCharacters);
// Output: <div data-reactroot="">fooanyCharacters</div>

Suspicion is this could be a candidate for Node.normalize()? If that was called before render to compact the text nodes, would it then still be necessary to use the HTML comment trick to end up with the same output? Thinking out loud here.. https://developer.mozilla.org/en-US/docs/Web/API/Node/normalize

Had this showing up in two places in a list of 100 things:
<!-- --> = 8 characters * 2 spots * 100 list items = 1600 extra characters

Gzip does eat this up though for sure, just seemed a bit odd. @gaearon thanks for the clarity!

@rhomoelle
Copy link

@buildbreakdo woah thx mate! Took me ages to find someone with the same problem. I use react as content building tool where the render output is imported into a more or less standardized software solution and those comments killed the upload.

@bernardobelchior
Copy link

For future reference:
I came here with the same problem, since I was using renderToString.
In my case, I don't need interactivity, so I ended up changing it to renderToStaticMarkup.
You can see the differences here.

@jamesarosen
Copy link

jamesarosen commented Oct 15, 2024

This is by design and helps React hydrate those text nodes correctly.

It may be by design. It may help hydrate more efficiently. But it's still a bug. HTML doesn't allow for comments in <title>.

react-dom doesn't use comments to set a textarea's value. This is invalid:

<textarea name="example">
  Some static text: {someDynamicValue}
</textarea>

React tells the developer to use defaultValue (for uncontrolled) or value (for controlled) textareas. Notably, it breaks if the user tries to use dynamic content inside a <textarea>. The feedback is immediate and the message is clear. It's also consistent with other similar elements like <input defaultValue={…} />.

Conversely, the message for <title> is unclear and is only a warning. Nothing is strongly pushing developers to apply the "correct" workaround for this bug. Nothing else in React prepares the engineer for the idea that <h1>{prefix} | {suffix}</h1> is valid react, but <title>{prefix} | {suffix}</title> is not. It's react internals leaking into user-space.

The docs for title say

children: <title> accepts only text as a child. This text will become the title of the document. You can also pass your own components as long as they only render text.

Assuming folks read the docs for such a small, seemingly-obvious element, that should probably read

children: <title> accepts only a single text node as a child. This text will become the title of the document. You can also pass your own component as long as it only renders text.

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

No branches or pull requests

5 participants