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

Why does Helmet recreate server rendered tags when it loads? #149

Closed
henrybaxter opened this issue May 31, 2016 · 22 comments
Closed

Why does Helmet recreate server rendered tags when it loads? #149

henrybaxter opened this issue May 31, 2016 · 22 comments
Labels

Comments

@henrybaxter
Copy link

Per the source here https://github.com/nfl/react-helmet/blob/master/src/Helmet.js#L197 I can see that Helmet blows away managed tags and re-adds them. Why does it do this? It leads to problems like this one http://stackoverflow.com/questions/37355346/script-tag-runs-twice-in-universal-react-application-fb-plugin/37555818#37555818 which is a problem that also affects me.

I'd be happy to submit a pull to change this behaviour, but thought perhaps there was a good reason. Thanks!

@cwelch5
Copy link
Contributor

cwelch5 commented Jun 1, 2016

@henrybaxter Thanks for bringing this to our attention. This is an issue that arises from the nature of react-side-effect because it re-renders every Helmet in the component tree because each one is unaware it is the last one in the tree. We are looking into fixing this by delaying the update of tags until the very last component so that it may update only once; then the checks we have put in place should prevent your script (or any other) tags from getting blown away unnecessarily.

As a workaround in the interim, if possible, put all your tags in the root and you'll see that tags coming from the server will not be removed and re-added.

@cwelch5 cwelch5 added the bug label Jun 1, 2016
@athomann
Copy link
Contributor

I've been dealing with an issue with server rendering memory leak with my components being duplicated and not being removed from memory. Would this be related?

@doctyper
Copy link
Contributor

@athomann I don't think that issue is related. Helmet does not duplicate components, it takes strings of data and converts them to HTML metadata.

@athomann
Copy link
Contributor

@doctyper It appears my issue has to do with react-side-effect and not calling .rewind

https://github.com/gaearon/react-document-title#server-usage

@ZeroCho
Copy link

ZeroCho commented Jul 28, 2016

+1
in my case, main.css which is my main stylesheet reloads and causes FOUC(Flash Of Unstyled Content)
my homepage link

I use both server side react-helmet(rewind) and client side react-helmet (<Helmet meta={config.meta} link={config.link} />) and what I guess is that client side react-helmet reloads links and causes FOUC

@pkieltyka
Copy link

Hello, just wondering if there's been any thought on this issue? Just because it will affect our tracking code

@cwelch5
Copy link
Contributor

cwelch5 commented Sep 21, 2016

The workaround until this bug is fixed is to put the server side tags you care about in the root of your app. Unfortunately this does take away the power of nesting at this moment, but those tags in the root will not get blown away on the client side.

@coreyleelarson
Copy link

Having the same problem.

@chibicode
Copy link

chibicode commented Oct 18, 2016

Had the same problem. I just ended up removing head.script.toString(). They won't be server rendered, but at least when client loads script tags are added to meta.

@evgenosiptsov
Copy link

evgenosiptsov commented Dec 9, 2016

I have some isssue, script loads twice on ${head.script.toString()} method. Problem has solve with using head script tag with async in on server instead at the end of html.

@marccoll
Copy link

Same here, first server renders head.script well. And then it renders the script again when all react js is fully loaded.

@evgenosiptsov
Copy link

evgenosiptsov commented Dec 24, 2016

There is a big problem. I spend some hours for research reason why react-router and redux after browserHistory.push() loaded twice with Provider, Router components and why partically I have errors "two valid but unequal nodes with the same data-reactid". It's broke all app's logic.

Using ${head.script.toString()} in the head tag does not solve this bug, we need possible to prevent loading bundle scripts twicely.

@evgenosiptsov
Copy link

evgenosiptsov commented Dec 24, 2016

So, there is a good approach to made environment checks like this:
<Helmet link={[ { rel: 'stylesheet', href: ${STATIC_DOMAIN}/assets/css/bundle-property.css}, ]} script={[ { src: !process.env.BROWSER ?${BUNDLES_DOMAIN}/bundle-for-server.js:${BUNDLES_DOMAIN}/bundle-for-browser.js, type: 'text/javascript', async: true }, ]} />

That would be good to have a ability to set params that enables rendering data through server or browser side. It should decide proble.

@cwelch5
Copy link
Contributor

cwelch5 commented Jan 17, 2017

My idea to fix this would be to have the first client-side render wait until all instances are mounted before it does it's client state change. To do that I'd need to hydrate the client with the number of instances to wait for. Any ideas on where and how the client should be hydrated?

I'm considering putting a data attribute on one/all the Helmet tags or just the html tag. Something like data-react-helmet-numMountedInstances. Open to better ways to hydrate the client, but definitely need to communicate the number of instances.

Of course, we could just skip the first client side render, that may be too loose as there may be a mismatch between server and client. At least allowing for one client change after the SSR, we can fairly compare, and in a best situation there should be no change.

Thanks for the input!

@doctyper
Copy link
Contributor

As of version 5, Helmet no longer re-creates tags if the server-rendered tags match their client-rendered equivalents. Relevant test: https://github.com/nfl/react-helmet/blob/master/test/HelmetDeclarativeTest.js#L3019-L3040

@jpetitcolas
Copy link

After facing the issue for long hours, note that rendering your scripts in the body causes a double rendering. I had to move them in the head section of my document, adding them a defer attribute to keep acceptable performances.

@mmcgahan
Copy link

mmcgahan commented May 13, 2017

@doctyper I'm just getting up to speed with this, but I don't think the test you referenced is a valid test comparing the recommended SRR {head.link.toComponent()} output to the client side output because the mock SSR tag in the test doesn't have a data-reactid attribute.

I'm running react-helmet@5.0.3, and the {head.link.toComponent()} call on the server returns the following markup:

<link data-react-helmet="true" rel="stylesheet" type="text/css" href="//0.0.0.0:8001/static/en-US/main.c1030da.css" data-reactid="5"/>

note the data-reactid="5" attribute.

I tried updating the test in test/HelmetDeclarativeTest.js, and it fails when the mock tag includes data-reactid.

This issue should probably be re-opened, or consolidated into #98

@roastlechon
Copy link

@mmcgahan I am also just now seeing this issue with the latest react-helmet.

isEqualNode seems to be the one causing me grief

@roastlechon
Copy link

After digging further, updateTags should not be called if my react elements are already server side rendered, but I need more information as to how it knows when to run updateTags

@roastlechon
Copy link

I moved my Helmet components higher up the tree and they seem to work as expected.

In my situation, I have an App component, i18n provider, redux provider, followed by a Layout component. Inside the layout component are divs which contain Helmet components.

There is also a routing piece that is used here which upon initial load (rehydrating from server), it seems to have trouble understanding that the elements were already there.

@Hellenic
Copy link

Also recently upgraded react-helmet to get rid of prop-types warning and then also came across with this issue. Tried both 5.0.0 and 5.1.3 and both have the same issue. Downgrading to 4.0.0 works again just fine.

@benkermode
Copy link

Using a Helmet server-rendered html page, loading a React app using Helmet, it seemed my CSS was being re-loaded, causing flashing.
I got around it like this. In the server-page component, a custom attribute:
<link data-block-helmet href=...../>

In the server-rendering script:
const strippedLinks = stripBlockedHelmetTags(helmet.link.toString());

And then the custom function, stripBlockedHelmetTags:

let tagArray = tagString.split('/>'); let strippedTagString = tagArray.map((tag)=>{ if(tag.indexOf('data-block-helmet="true"') > -1){ return tag.replace(/data-block-helmet="true" /g, '').replace(/data-react-helmet="true" /g, ''); } else { return tag; } }).join('/>'); return strippedTagString;

Basically strips out the data-react-helmet attribute and Helmet leaves it alone. Let me know if this is useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests