"React attempted to reuse markup" error with webpack + code splitting - reactjs

I've started implementing code splitting in an "universal" app (react-router, redux, webpack - largely based on https://github.com/erikras/react-redux-universal-hot-example).
On the (only) route where code splitting is implemented, I am getting the following React error message when doing a full browser refresh:
warning.js:44Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) <!-- react-empty: 1 -
(server) <div class="root" dat
If I disable code splitting, the error message goes away. I am guessing this is due to React doing a first render before the Javascript chunk was loaded by the Webpack loader and therefore, it generates markup that is different from the one generated on the server. Is that correct?
Should I worry about the error message?
Any way to figure out what React renders to at the exact time this message occurs?
Any fix to make the message go away? (other than to not use code splitting)

The solution is to call react router's match function before doing the first render.
See https://github.com/reactjs/react-router/issues/2036#issuecomment-225792937 and https://github.com/reactjs/react-router/blob/v2.4.1/docs/guides/ServerRendering.md#async-routes

Should I worry about the error message?
Yes, if React determines the mark-up differs it'll fail to re-use any of the existing mark-up and instead re-generate it from the client render resulting in more work for the browser.
Any way to figure out what React renders to at the exact time this message occurs?
You can compare the differences by diffing the generated source in dev tools and the html sent over the network.
Any fix to make the message go away? (other than to not use code splitting)
You could call match as you've suggested in your answer or alternatively, if you happen not to be using React Router or your split points aren't setup via the router you could load all required chunks up front, e.g.
<!-- index.html -->
<script src="entry.js"></script>
<script src="chunk1.js"></script>
<script>
// NOTE: Instead of calling render immediately in `entry.js` you would need to define a function on the global to allow you to render the app after the second chunk has loaded.
window.App.render();
</script>
NOTE: This would only work when using require.ensure because System.import / import is always async which would mean the mark-up would still differ on the very first render.

Related

What does the CSP nonce implementation look like?

I've been reading CSP stuffs recently, but I failed to find a clear explanation or solid example about how nonce gonna work. I tried to avoid using unsafe-inline for security concerns.
So far, my understanding is like the following:
A server will generate a new nonce every connection
A client gets this nonce by a certain way and inserts this string into each script tag
However, I have no idea how the client will get this value which is dynamic and unique among each connection. What is a certain way be like? Should I implement an extra API to get this value?
I used React.js and there's a Google Tag Manager snippet in my HTML head, if someone can provide the example related to these would be perfect.
React applications is a SPA(Single Page Application) so content is loaded using XMLHttpRequest() and inserted without page reloading. Therefore 'nonce-value' is not used since you have no way to generate a new 'nonce' each time page refreshing.
The 'nonce' can be used when SSR (Server Side Rendering), in this case server can gererate fresh 'nonce' value and insert it into HTML code been sent (into <script nonce='value'>, <script src ='some_url' nonce='value'>, <style nonce='value'> and <link href='some_url' nonce='value' rel='stylesheet'>).
For this reason, React applications use 'hash-value' to allow inline scripts and styles.
For example react-static-plugin-csp-meta-tags package adds a CSP meta tag to your html files and adding hashes for all inline script and style tags.

Putting event handlers inside NextJS _document -- and relationship between NextJS pages and React SPA

I'm learning NextJS and am trying to wrap my head around the difference between server-rendered and client-side React code -- while NextJS seems great, I'm having some trouble conceptually understanding the difference between the two types of rendering and what those differences mean.
For instance, I came across the following comment in the NextJS documentation, in the section describing `_document``
// _document is only rendered on the server side and not on the client side
// Event handlers like onClick can't be added to this file
Why can one not put event handlers in _document? What is the difference between this and putting them 'client side'?
Also I'm somewhat confused because NextJS seems to be oriented around building 'pages' -- that is, there's support for adding <HEADER>, etc, as if we were building a static website. But if I were to build a React SPA, there's only one page, no? One can simulate different 'pages' using the React router, but the actual containing HTML (header, body, etc) remains the same, no? That is, we never really leave the actual HTML page?
I can use NextJS OK -- following through the documentation's tutorials -- but clearly conceptually I'm missing the forest for the trees. Any clues or pointers much appreciated!
pages/_app.js is where you need to client-side codes. It is shared between all pages.
pages/_document.js only runs in SSR. so you need to put relevant code there.
Saying that, you only need to create these pages if you need to modify the normal behaviour of the app and customise it in your way.
SSR means Server side rendering and it happens when you type url in urlbar and press enter or when you refresh the page with refresh button.
CSR Client Side Rendering on the other hand is the way of SPA(single page app). so the URL change but there is no server call. It look for resources in pages directory for routing.
Next HEAD is way to manipulate the header tags like meta, title etc. in every page. It will give you freedom of customising head tag.

isomorphic/universally-rendered React 15 app breaks with Cloudflare HTTP Proxy ("orange cloud")

I have an isomorphic/universal React app, meaning it is rendered on the server by the same JS that powers the client-side, Single Page App user experience.
I configure this app's DNS using Cloudflare, and use their "orange cloud" feature to accelerate and protect my site's traffic, as explained in the following graphic and in their support article:
From the linked-to article: "Cloudflare can operate in two modes - DNS only (unproxied; 'grey cloud') and as a HTTP proxy ('orange cloud') with our security, CDN & performance features."
I have discovered that running my app with React 15 and Cloudflare's "orange cloud" HTTP Proxy feature results in an error:
reactProdInvariant.js:31 Uncaught Error: Minified React error #32; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=32&args[]=2 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
The text of the linked-to bug:
Unable to find element with ID 2.
This ID probably refers to the head tag of my page:
<!doctype html>
<html lang="en-us" data-reactroot="" data-reactid="1" data-react-checksum="-1233854461"><head data-reactid="2">...
I do NOT get this issue with React 14.
I do NOT get this bug when using the raw, un-DNS-ed address of my app, nor do I get it when I switch to the "grey cloud" to use Cloudflare as only a DNS service.
I do NOT get this issue when I disable server-side rendering.
When I google the text of the linked-to "actual" error, I find this Github thread that confirms that this has something to do with server-side rendering.
However, my situation differs slightly: that thread's author encounters the error with an "unable to find element" ID referring to a style tag, whereas in my case the unfound element ID refers to the head tag.
When I google the text of the production "wrapped" error, I find this Github thread that confirms that this has something to do with Cloudflare's HTTP Proxy. This comment says: "If you're using CloudFlare, please disable auto-minification of HTML."
So far, I can't figure out how to do that. It's hard for me to find good information on what exactly Cloudflare does with their HTTP Proxy, and how I can configure it.
Questions:
Why exactly does this bug happen?
Where can I find information about what exactly the "orange cloud" does?
What is the best way to fix this problem while maintaining the benefits of Cloudflare's HTTP Proxy?
React on the server needs to render the application to a string of HTML that makes sense to the browser. At the same time, React in the browser needs to read this HTML and understand it in relation to your JS code: it needs to identify which DOM tree came from which React component, in a very detailed way. Thus, in effect, the intermediate HTML is a serialization format between React on the server and React on the client with an additional requirement for it to make sense for the browser even in the absence of React.
When you enable advanced Cloudflare functionality, it treats the HTML as a “regular” HTML, not fancy server-side rendered compnents. My baseless speculation on one thing that could be going wrong is stripping HTML comments. In general, this is a natural thing to do for minification. But React uses HTML comments to put a <!-- empty --> placeholder where a React component returns null. Naturally, stripping these breaks React.
Cloudflare is there to make serving websites faster at a lower cost. They have a wide variety of tools to achieve that, see their introduction guide. Minifying HTML is completely natural and it is unfortunate it breaks your use case, but this is what we get when the meaning of nodes and attributes and flexibility changing them in our HTML is not strictly defined.
I think the most straight-forward way for you to move forward for now is to disable HTML minification in Cloudflare settings.

React server and client rendering

Using https://github.com/ayoubdev/reactjs-isomorphic-starterkit as a boiletplate.
I'm trying to figure out how to inject the client's bundle into the server rendering process.
As the webpack build for server and client is well separated, is there a simple trick to achieve this goal ?
Thanks
I'm not too sure about the specifics of this boilerplate repo. But I can try to explain the main idea, and you can dig deeper.
The basic idea is, use a bundler (in this case, webpack is used, gulp, grunt, whatever else is fine as long as you transpile) and build a bundle based on the entry point for your React components. Then link this bundle via script tag in some html file.
For the server side, you can use ReactDOMServer.renderToString. Import your component(s), pass them into ReactDOM.renderToString. Pass the HTML to some templater like ejs or use a raw HTML string and call React.render from the server.
Client side.
In your example, the entry point is here and hooked here. Notice the <div class= "app"> tag. This is tag we are referencing in our entry point. We also reference our bundled js from webpack via script tag, client.bundle.js.
Server side
In your example, the relevant code is here. Notice the renderComponent function. It builds a string based on the HTML of the component supplied from ReactDOMServer.renderToString, which is called on Line 39. It then sends all of that html back as a response in res.send
This blog article uses jade as an example, which you can use as an alternative if you find this boilerplate a bit much.

Rendering noscript version serverside without reuse markup warnings in React

In my JS component I currently render the non-js version of the markup for compatibility with old browsers. Then Client-side this is re-rendered to the js-on markup.
This causes the error below where you can see the noscript version triggers this error.
Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) <div class="shortlist ...
(server) <noscript data-reacti ...
Is there a way to resolve this issue where the client gets the fastest experience while maintaining support for noscript browsers?
My solution was to replace <noscript> with <div id="noscript" ref="noscript"> and in componentDidMount call this.refs.noscript.style.display = 'none';.
To hide the noscript div ASAP I've also added <script>try{document.getElementById('noscript').style.display='none'}catch(e){}</script> to the index.html just immediately after placeholder for serverside rendered markup.

Resources