title: Webpack bundle Node Express with hot reloading = hell
body: <p>I hate to admit it, but I've been spending three long evenings trying to do - what I thought would be straightforward thing to do. I finally reached the stage where I'm fed up with it, and frankly rather frustrated because "it just won't work". </p>
  
  <p>Here is what I try to achieve:   </p>
  
  <ol>
  <li>Bundle my Express server with Webpack (although my current code just renders a string in the browser, it is supposed to compile server rendered React components compiled with Babel)  </li>
  <li>Save the bundle in memory (or on disk if there is no other way)  </li>
  <li>Run webpack / dev / hot middleware to serve my Node Express app in a way that changes to the server rendered pages (which will be React components) will auto-update in the browser.  </li>
  </ol>
  
  <p>I've tried numerous combinations, tutorials that have been deprecated, npm packages that are no longer maintained and downloaded examples that just don't work.  </p>
  
  <p>Here is my current setup: </p>
  
  <p>webpack.server.config.js: </p>
  
  <pre><code>const path = require('path');
  const webpack = require('webpack');
  const nodeExternals = require('webpack-node-externals');
  
  module.exports = {
      name: 'server',
      mode: 'development',
      target: 'node',
      externals: nodeExternals(),
      entry: [ './src/server/index' ],
      output: {
          path: path.resolve(__dirname, 'dist'),
          // path: "/",
          filename: '[name].js',
          publicPath: '/assets/',
          libraryTarget: 'commonjs2'
      },
      plugins: [
          new webpack.HotModuleReplacementPlugin()
      ],
      module: {
          rules: [
              {
                  test: /.js$/,
                  loader: 'babel-loader',
                  include: path.resolve(__dirname, 'src/'),
                  exclude: /node_modules/,
                  options: {
                      presets:
                          [['@babel/preset-env', { modules: 'false' }], '@babel/preset-react'],
                      plugins: [
                          ['@babel/plugin-proposal-object-rest-spread', { useBuiltIns: true }],
                          '@babel/plugin-proposal-class-properties'
                      ]
                  }
              },
              {
                  test: /\.scss$/,
                  loader: 'ignore-loader'
              },
              {
                  test: /\.css$/,
                  loader: 'ignore-loader'
              },
              {
                  test: /\.(jpg|png|svg|gif|pdf)$/,
                  loader: 'file-loader',
                  options: {
                      name: '[path][name].[ext]'
                  }
              }
          ]
      }
  };
  </code></pre>
  
  <p>index.js: </p>
  
  <pre><code>import http from 'http';
  import fs from "fs";
  import express from "express";
  import favicon from 'serve-favicon';
  // import renderer from "./renderer";
  import renderApp from './welcome';
  
  
  const app = express();
  
  app.use(favicon('./public/favicon.ico'));
  app.use(express.static("public"));
  
  
  if (process.env.NODE_ENV !== 'production') {
  
      const webpack = require('webpack');
      const webpackDevMiddleware = require('webpack-dev-middleware');
      const webpackHotMiddleware = require('webpack-hot-middleware');
      const serverConfig = require('../../webpack.server.config');
  
      const compiler = webpack(serverConfig);
  
      app.use(webpackDevMiddleware(compiler, {
          stats: {colors: true},
          headers: { "Access-Control-Allow-Origin": "http://localhost"},
          publicPath: serverConfig.output.publicPath
      }));
  
      app.use(require("webpack-hot-middleware")(compiler));
  
  }
  
  app.get("*", function(req, res) {
      fs.readFile("./src/server/html/index.html", "utf8", function(err, data) {
          const context = {};
          const html = renderApp();
          //const html = renderer(data, req.path, context);
  
          res.set('content-type', 'text/html');
          res.send(html);
          res.end();
      });
  });
  
  const PORT = process.env.PORT || 8080;
  
  app.listen(3000);
  </code></pre>
  
  <p>Frankly I'm also rather confused about how this is supposed to work.<br>
  Are the following steps supposed to be executed?: </p>
  
  <ul>
  <li>webpack webpack.server.config.js --watch </li>
  <li>node dist/server.js // webpack output folder</li>
  </ul>
  
  <p>Would this magically hot reload my server?  </p>
  
  <p>All help is welcome, or if you happened to have a working demo.<br>
  I just couldn't manage to make this work.  </p>
  
  <p>In the end I will also hot reload (re-render) my client bundle but I guess that will be the easy part as I've seen many, many resources about that.  </p>