RickWong / react-isomorphic-starterkit

Create an isomorphic React app in less than 5 minutes
BSD 3-Clause "New" or "Revised" License
2.32k stars 191 forks source link

Server-side rendering question. #94

Closed chemoish closed 8 years ago

chemoish commented 8 years ago

I am trying to understand how modifying containers or components (HMR) after the server-side rendering doesn't fire this error.

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:

Any insight or direction would be much appreciated.

(Not sure if it has anything to do with koa or concurrently running webpack server.js or webpack-dev-server client.js—I did notice there was something done here: https://github.com/RickWong/react-isomorphic-starterkit/commit/98965026107826a7d7ff099454ddb2a5c639c9fd)

RickWong commented 8 years ago

This is how npm run watch works:

Server-side Webpack HMR enables watching and refreshing of the require module cache (hence hot module reloading) so the next time an http request hits the Koa app, Node will get the updated module and therefore run the updated component. All without having to restart Node or the Koa app.

In the meanwhile the Webpack-Dev-Server has also rebuilt client.js for the client-side so when that script is served again, it will also contain the new code as well.

Does this answer your question?

chemoish commented 8 years ago

Server-side Webpack HMR enables watching and refreshing of the require module cache

This is where I am not following.

I understand that the server.js is being watched and rebuilt on file change (Though not sure how exactly that is being done [I am guessing its watching the entire tree built by import routesContainer from "containers/routes";]), but in my very similar implementation, it is not acting the same.

(I am trying to emulate the functionality with Redux, ReduxRouter, Express to keep it simple)

Differences:

RickWong commented 8 years ago

A few things can be wrong. 1) You must run dist/server.js which is the result of a Webpack build that adds HMR. If you run src/server.js then there's no Webpack HMR. Make sure you have all the latest npm run commands: https://github.com/RickWong/react-isomorphic-starterkit/blob/80f75a9ba676c0e3f1b29eff604f500fc77f6c22/package.json#L28-L31 and just run npm run watch 2) You're not using Transmit. Are you sure the server renders using the same data (Redux state) as the client? Try "View Source" on the page and look for missing data.

I can help you debug this more but only if you upload the code to a GitHub repository or gist. Without the code, I can only make a guess at what's wrong. Guessing is not really efficient :/

chemoish commented 8 years ago

Yea, sorry about that. Let me investigate a bit more then I will upload something more tangible.

Thanks greatly!

chemoish commented 8 years ago

Here it is, it's kind of mangled due to following 4 starter kits to figure out this secret, but should mostly follow your configuration.

https://github.com/chemoish/react-isomorphic-starterkit-fail

chemoish commented 8 years ago

First issue is https://github.com/chemoish/react-isomorphic-starterkit-fail/blob/master/package.json#L10, needs to be server-start (Hella big mistake to not fire the hot plugin).

This allows the module.hot to work. I suspect https://github.com/RickWong/react-isomorphic-starterkit/blob/master/src/server.js#L74-L79 is doing the magic.

Still having issues on my end, but hacking away.

socomplex

chemoish commented 8 years ago

The missing piece. https://github.com/RickWong/react-isomorphic-starterkit/blob/master/src/containers/routes.js#L9

import functionality doesn't allow you to modify the import. Therefore you have assigned it to a let. This allows you to modify the routes delivered to the server by refreshing the content that gets sent to the server via require('containers/routes').

However, you need to update routes.js to export in non-es6 since import is only available at the top of the file (I think).

Thanks for your help.

RickWong commented 8 years ago

import disallows reassignment of the used variable name. So yes, that's why routes.js is included via require() the old way.

It's unfortunate that it depends on such little differences, like having to use module.exports, that it works or fails to work. require().default would have worked too, but it looks weird. I'm sure JavaScript will grow up in 2016 and get rid of these issues. I'm glad you found it and solved it in your project!