Step By Step Guide to Enable Hot Module Replacement in a Custom Server-Side Rendered React App
Requirement —
- Pages should be initially rendered at server side using some templating engine like EJS and some initial data injected into the page by the server.
- Express should be used as the web server, along with all the backend logic, and use that to render the views on initial page load.
- React code should be separated, and whenever changes are made to react components code/css, ui should be updated on the fly, without refreshing the page. read more about HMR
Dependencies
ejs: used for server side templating
express: our server
react, react-dom: for rendering react components
Dev Dependencies
Babel stuff: to transpile our JSX to javascript
loaders: loaders for webpack to resolve different module types.
@pmmmwh/react-refresh-webpack-plugin: webpack plugin to enable HMR for react components, without loosing state.
webpack stuff: to bundle our app and enable hot module replacement.
Webpack Config
Nothing much different here. Webpack config is same as you would use for client side rendered app, powered by webpack dev server. Make sure that the entry points to the index.js where you have rendered your react root using ReactDOM.render
Client Side react code —
Nothing different here too. Just normal client side react code.
Server Side code
This is the interesting part. The problem in hot reloading a server side rendered app is that we have no way to connect it to the webpack-dev-server which enables HMR! because we are running it inside an express server, which knows nothing about webpack. here comes to our rescue webpack-dev-middleware and webpack-hot-middleware. These middlewares stick to the express app and enable the hot reloading.
Notice line 3–5 and 12–16. We import these modules and put them as normal middlewares of express. Also note that we pass the webpack config as argument to webpack [line 8] and then pass the compiler instance to these middlewares. [lines 12 and 16]
server.js
a sample view
notice on line 49, we include the bundle.js. This will be updated by webpack using the setup we did. Rest of the code is rendered server side. We can put whatever logic we want here. Notice line 41 and 44. These are dynamic values injected into ejs view by express server. See line 20 in server.js above. These can be any data processed or fetched at server side and injected into the ejs view. We can also use this data to hydrate the initial state of redux store. Say to validate the cookie and authenticate the user etc. We can also use this to optimize the critical rendering path, say inlining css for above the fold content, rendering above the fold content etc.
Thats it. You are good to go. Just run node index.js and your app should be up and running with hot module replacement enabled.
The complete code is available at https://github.com/ktajpuri/ssr-hot-reloading.
Feel free to ask any questions in comments.