Initial Webpack configuration

First we should install our dependencies:

npm i express react react-dom

and our development dependencies:

npm i -D webpack webpack-cli webpack-node-externals babel-core babel-loader babel-preset-es2015 babel-preset-react babel-plugin-transform-class-properties

other tools that will helps us in development:

npm i -D concurrently nodemon

Let’s configure Webpack. We will need two Webpack configurations, one for the Node.js server code and another one for the client code. If you want to see the structure of our app, please refer to the repository. Also, please note that:

I’m using the ES2015 preset instead of the new env preset, you can change it on your own if you want to. I’ve also included the transform-class-properties Babel plugin so I don’t need to .bind my classes methods everywhere. It's up to you if you want it, but it's on CRA by default.

Since I’m using the same module rules for both server and client I will extract them to a variable js :

Note that in both configurations I’m using different targets.

On the server configuration, there are two details I’ve missed in my previous attempts to do server-side rendering and by doing so I was not able to even build my app: The node.__dirname property and the use of the Webpack plugin webpack-node-externals.

In the first case I’ve set __dirname to false so when Webpack compile our server code it will not provide a polyfill and will keep the original value of __dirname , this configuration is useful when we serve static assets with Express, if we don't set it to false Express will not be able to find the reference for __dirname .

The webpack-node-externals is used so Webpack will ignore the content of node_modules , otherwise, it will include the whole directory in the final bundle. (I'm not sure why it's not the default behavior and we need an external library for this. My understanding is that if you have set your configuration target to node, it should have kept the node_modules out of the bundle.)

Note: In both cases, I found the documentation really confusing so please don’t take my word for it and check the docs yourself in case of further questions.

and our client configuration:

Finally, we will export both configurations:

module.exports = [serverConfig, clientConfig]

You can find the final file here.