Isomorphic Express / React development setup

Kim Gysen
4 min readJun 1, 2019

--

This article describes a simple setup that I have made for hot reloading my isomorphic webapp that is capable of auto-refreshing the browser. It is not perfect, but can easily be modified and adapted as desired.

If you disagree, have proposals for improvement, or a better idea on how you would build your setup, don’t hesitate to share it in the comments.

TLDR;

Head over to the github repo that I prepared: https://github.com/kimgysen/isomorphic-react-setup

There are 2 branches:

  • master: Hot reload the browser with reload.js
  • webpack-dev-middleware: Hot reload the browser with webpack-dev-middleware and webpack-hot-middleware

Installing and starting either develop or production builds is easy.

Git clone and checkout a branch:

git clone https://github.com/kimgysen/isomorphic-react-setup.git
checkout master // (which you're already in, basically)
// or
checkout webpack-dev-middleware

In either branch the procedure is the same: install node modules and start the application:

npm install 
npm run start:iso:dev
// or
npm run start:iso:prod

Both the server and client code is Babel compiled with Webpack.

The production build splits up npm modules in different chunks so that the browser can cache them separately, and they can be updated individually in the future when the user browses the website on subsequent requests.

Motivation

‘Isomorphic’ or ‘universal’ web apps refer to apps that render html from the server, and then hydrate the rendered html in the client based on a Javascript bundle that you send along. The benefits are basically fast page rendering and SEO.

I’m a proponent of investing time in a proper setup to save time during the development process because I believe that you will get that time back in plural afterwards. This is twice true if you’re planning to work on multiple projects in the future.

In practical terms it means that changes to the source code will automatically be reflected in the browser without the need for any manual interventions in terms of restarting the server, or refreshing the browser.

Webpack-dev-middleware / Webpack-hot-middleware

The most obvious option that I explored was the middleware that I mentioned in the title. This middleware works great, although I bumped into 1 minor problem.

The following gif shows how I start the app in dev mode, and update some text in the ‘Home’ component. The update works great, but an exception is thrown in the console:

Hot reloading with webpack-dev/hot-middleware

The reason why this exception appears is because the html rendered from the server was not reloaded, contrary to the html rendered by the client.

A common solution to this problem is to ‘hide’ the exception by just rendering at the client rather than hydrating the html that is returned from the server when we’re running develop mode.

The downside of this is that hydration issues are not visible. In production there shouldn’t be any, since we’re rendering the same common component on the server and the client so this solution may be completely acceptable. The other thing is that sever changes are not recompiled either, so you will still need to restart the server to see those changes, or use a tool like Nodemon (which after trying it I didn’t find to offer a great workflow when we’re compiling the server with Webpack).

Reload.js

While I was looking at some options, I bumped in the following nice npm library: https://github.com/alallier/reload. As the README says:

Automatically refresh and reload your code in your browser when your code changes. No browser plugins required.

The library basically allows you to watch the filesystem and reload the browser on file changes using a websocket connection, but it also allows you to reload the browser manually from code.

So basically my idea was to use Webpack the HotModuleReplacementPlugin in combination with this library.

The following gif shows that it works. Server rendered html now corresponds to the html expected by the client, and other changes on the server are recompiled as well:

Components are rendered without hydration issues
Server updates are compiled on the fly

The downside is that bundles are written to disk so it won’t be as fast as served from memory. In order to clean up the dist folder, I used the clean-webpack-plugin so you won’t be flooded with hot-update files.

Conclusion

Which one is better? I leave it up to you to decide.

This code is far from perfect as I haven’t spent my time on optimisations, but I believe it to be a good entry point to get started with isomorphic apps, and I hope it will help people to get up and running with new projects quickly.

--

--