react-helmet-async: Helmet tag not being updated in production with server rendering
HI @staylor! While implementing this library with server rendering, I am noticing that while the updated tags show up in the server-rendered code in development, they do not do show up in production.
Here is my code on the server side. Specifically helmetContext.helmet.meta.toString shows up as empty in production while it works perfectly fine in development. I’m on React 16.5.2, Webpack 4.16 and Node 10.
// Holds Helmet state specific to each request
const helmetContext = {}
// Declare our React application.
const app = (
<AsyncComponentProvider asyncContext = { asyncComponentsContext }>
<JobProvider jobContext = { jobContext }>
<StaticRouter location = { request.url } context = { reactRouterContext }>
<HelmetProvider context = { helmetContext } >
<Provider store = { store }>
<CookiesProvider cookies = { request.universalCookies }>
<UserAgentProvider ua = {request.headers["user-agent"]} >
<IntlProvider
locale = { locale }
messages = { messages }
initialNow = { Date.now() }
textComponent = { Fragment }
>
<Route component = { App } />
</IntlProvider>
</UserAgentProvider>
</CookiesProvider>
</Provider>
</HelmetProvider>
</StaticRouter>
</JobProvider>
</AsyncComponentProvider>
)
// ℹ️ First we bootstrap our app to ensure the async components/data are resolved
await asyncBootstrapper( app )
const jsx = sheet.collectStyles( app )
const stream = sheet.interleaveWithNodeStream(
renderToNodeStream( jsx ),
)
// Resolve the assets (js/css) for the client bundle's entry chunk.
const clientEntryAssets = getClientBundleEntryAssets()
const { helmet } = helmetContext
/*
* all of the things in the params below are included in the header
* can add htmlAttributes & bodyAttributes from Helmet if needed
*/
const paramsForHeader = {
titleTag: helmet.title.toString(),
metaTags: helmet.meta.toString(),
linkTags: helmet.link.toString(),
cssBundle: clientEntryAssets && clientEntryAssets.css,
nonce,
}
console.log( "metaTags toString:", helmet.meta.toString()) // nothing
console.log( "metaTags toComponent", helmet.meta.toComponent()) // nothing either
/*
* all of the things in the params below are included in the footer
*/
const paramsForFooter = {
storeState: store.getState(),
routerState: reactRouterContext,
jobsState: jobContext.getState(),
asyncComponentsState: asyncComponentsContext.getState(),
jsBundle: clientEntryAssets.js,
clientConfig,
polyfillPath,
nonce,
}
switch ( reactRouterContext.status ) {
case 301:
case 302:
// ...
break
case 404:
// ...
break
default:
// Otherwise everything is all good and we send a 200 OK status.
response.status( 200 )
response.type( "html" )
response.setHeader( "Cache-Control", "no-cache" )
response.write( Head( paramsForHeader ))
stream.pipe( response, { end: false })
stream.on( "end", () => response.end( Footer( paramsForFooter )))
}
Any ideas what might be going on?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Reactions: 1
- Comments: 15 (2 by maintainers)
The problem is it is a stream, and it is async process. the moment your read the variable the stream is not done for read yet. Therefore you need to attach event
on('end', cb)on this stream, so you could see the value. See my sample implementation here.As you can see we pipe body, then write head and footer because we need to process body first. That’s why we need to use transform stream to flip it back to proper order. Here is simple implementation for
HTMLTransform.Just checking if there were any updates on this, I am currently having a similar issue. Any of my helmet tags are always empty.
<title data-rh="true"></title>Looks like the main contributor of this app isn’t really active… thanks for putting this out here… It would be great if you engaged with some of your followers here @staylor
I am having the exact same issue, working from the minimal example on React 16.8.2 and node 9.6. This happens every time I try to use it
@oyeanuj are you streaming? Check out #3
@staylor I noticed that what seems to be happening is that the render method of the child component in the tree which has the meta tags hasn’t been invoked in time for the call to
helmet.meta.toString()above.Do you think race conditions are a possible reason? Or is there another way to structure it to ensure that RHA has gone thru the tree and traversed the render of all child components?